1 #include <stdio.h>
  2 #include <string.h>
  3 #include <sys/epoll.h>
  4 #include <stdlib.h>
  5 #include <unistd.h>
  6 #include <time.h>
  7 #include <errno.h>
  8 #include <signal.h>
  9 #include "rh_event.h"
 10 #include "rh_bitset.h"
 11 #include "log.h"
 12 
 13 
 14 static rh_event_t * rh_event_signal [NSIG] = {0, };
 15 
 16 
 17 
 18 static int rh_event_ep2rh (int   ep_events);
 19 static int rh_event_rh2ep (short rh_events);
 20 
 21 static void rh_event_signal_handler(int sig)
 22 {
 23         if (NULL == rh_event_signal[sig])
 24                 return;
 25 
 26         /*
 27          *
 28          * this is only the simple way.
 29          *
 30          * if there are more event bases then not the correct event is called.
 31          *
 32          * use the socketpair() stuff like in libevent.
 33          *
 34          */
 35         
 36         rh_event_signal[sig]->cb (sig, RH_EVENT_SIGNAL,
 37                         rh_event_signal[sig]->arg);     
 38 }
 39 
 40 int rh_event_base_init (struct rh_event_base *base, int timeout)
 41 {
 42         memset (base, 0, sizeof(*base));
 43         
 44         TAILQ_INIT(&base->timeout_list);
 45 
 46         base->fd = epoll_create (100);
 47         if (base->fd == -1) {
 48                 return -1;
 49         }
 50                 
 51         base->timeout = timeout;
 52 
 53         return 0;
 54 }
 55 
 56 void rh_event_base_exit (struct rh_event_base *base)
 57 {
 58         ++base->exit;
 59 }
 60 
 61 void rh_event_base_destroy (struct rh_event_base *base)
 62 {
 63         if (base->fd > -1) {
 64                 close (base->fd);
 65                 base->fd = -1;
 66         }
 67         
 68         if (base->nodes) {
 69                 size_t i;
 70         
 71                 for (i=0; i<base->nodes_count; ++i) {
 72                         if (base->nodes[i]) {
 73                                 free (base->nodes[i]);
 74                                 base->nodes[i] = NULL;
 75                         }
 76                 }
 77                 
 78                 free (base->nodes);
 79                 base->nodes = NULL;
 80         }
 81 }
 82 
 83 int rh_event_dispatch (struct rh_event_base *base)
 84 {
 85         while (0 == base->exit) {
 86                 struct epoll_event      ep_events[100];
 87                 int                     nep_events, i;
 88                 time_t                  time_current;
 89 
 90                 nep_events = epoll_wait(base->fd, ep_events, 100, 900);
 91 
 92 #if 0
 93                 printf ("%s(%p): %d events\n", __FUNCTION__,
 94                                 (void*)base, nep_events);
 95 #endif
 96                 
 97                 base->time = time_current = time(NULL);
 98 
 99                 if (-1 == nep_events && errno != EINTR)
100                         return -1;
101                         
102                 /* process events */
103                 for (i=0; i < nep_events; ++i) {
104                         struct rh_event_node    *node;
105                         short                   rh_events;
106                         int                     fd;
107 
108                         rh_events = rh_event_ep2rh (ep_events[i].events);
109 
110                         fd = ep_events[i].data.fd;
111                         
112                         node = base->nodes[fd];
113 
114                         if (    node->read &&
115                                 rh_events & (RH_EVENT_READ | RH_EVENT_ERROR) )
116                         {
117                                 if (node->read->rh_events & RH_EVENT_TIMEOUT) {
118                                         
119                                         if (node->read != TAILQ_LAST(
120                                                         &base->timeout_list,
121                                                         rh_event_list))
122                                         {
123                                                 TAILQ_REMOVE(
124                                                         &base->timeout_list,
125                                                         node->read,
126                                                         list);
127                 
128                                                 TAILQ_INSERT_TAIL(
129                                                         &base->timeout_list,
130                                                         node->read,
131                                                         list);
132                                         }
133         
134                                         node->read->timeout_time = time_current;
135                                 }
136 
137                                 node->read->cb(fd, rh_events,node->read->arg);
138                                 
139                         }
140                         
141                         if (    node->write &&
142                                 rh_events & (RH_EVENT_WRITE| RH_EVENT_ERROR) )
143                         {
144                                 if (node->write->rh_events & RH_EVENT_TIMEOUT) {
145                                         if (node->write != TAILQ_LAST(
146                                                         &base->timeout_list,
147                                                         rh_event_list))
148                                         {
149                                                 TAILQ_REMOVE(
150                                                         &base->timeout_list,
151                                                         node->write,
152                                                         list);
153                         
154                                                 TAILQ_INSERT_TAIL(
155                                                         &base->timeout_list,
156                                                         node->write,
157                                                         list);
158                                         }
159         
160                                         node->write->timeout_time = time_current;
161                                 }
162                                 
163                                 node->write->cb(fd, rh_events,node->write->arg);
164                         }
165                 } /* for (events) */
166 
167                 /* timeout */
168                 for (;;) {
169                         struct rh_event *event;
170 
171                         event = TAILQ_FIRST(&base->timeout_list);
172 
173                         if (NULL == event)
174                                 break;
175 
176                         if (time_current - event->timeout_time < base->timeout)
177                                 break;
178 
179                         DEBUGLOG("timeout. event(%p) fd(%d)",
180                                         (void*)event,
181                                         event->fd);
182 
183                         event->cb(event->fd, RH_EVENT_TIMEOUT, event->arg);
184                 }
185         }
186         
187         return 0;
188 }
189 
190 static int rh_event_rh2ep (short rh_events)
191 {
192         int ep_events = 0;
193 
194         if (rh_events & RH_EVENT_READ)
195                 RH_BIT_SET(ep_events, EPOLLIN | EPOLLPRI);
196 
197         if (rh_events & RH_EVENT_WRITE)
198                 RH_BIT_SET(ep_events, EPOLLOUT);
199 
200         if (rh_events & RH_EVENT_ERROR)
201                 RH_BIT_SET(ep_events, EPOLLERR | EPOLLHUP);
202         
203         if (rh_events & RH_EVENT_ET)
204                 RH_BIT_SET(ep_events, EPOLLET);
205 
206         return ep_events;
207 }
208 
209 static int rh_event_ep2rh (int ep_events)
210 {
211         int rh_events = 0;
212 
213         if (ep_events & (EPOLLIN | EPOLLPRI))
214                 rh_events |= RH_EVENT_READ;
215 
216         if (ep_events & EPOLLOUT) 
217                 rh_events |= RH_EVENT_WRITE;
218 
219         if (ep_events & (EPOLLERR | EPOLLHUP))
220                 rh_events |= RH_EVENT_ERROR;
221 
222         return rh_events;
223 }
224 
225 static int rh_event_node_resize (struct rh_event_base *base, size_t nodes_count)
226 {
227         struct rh_event_node    **nodes;
228         size_t                  i;
229 
230         if (nodes_count < base->nodes_count)
231                 nodes_count = base->nodes_count + 1;
232         
233         nodes_count = nodes_count + 128 - (nodes_count % 128);
234 #if 0
235         printf ("%s(): %u -> %u\n", __FUNCTION__,
236                         base->nodes_count, nodes_count);
237 #endif
238         nodes = realloc (base->nodes, nodes_count * sizeof(nodes));
239 
240         if (NULL == nodes)
241                 return -1;
242 
243         for (i=base->nodes_count; i<nodes_count; ++i) {
244                 nodes[i] = calloc(1, sizeof(struct rh_event_node));
245                 if (NULL == nodes[i]) {
246                         /* nothing? */
247                 }
248         }
249 
250         
251         base->nodes = nodes;
252         base->nodes_count = nodes_count;
253         
254         return 0;
255 }
256 
257 
258 int rh_event_set (struct rh_event *event, struct rh_event_base *base,
259                   int fd,
260                   short events,
261                   void (*cb)(int, short, void *),
262                   void *arg)
263 {
264         if ( (events & RH_EVENT_SIGNAL) ) {
265                 event->node = NULL;
266         } else {
267                 if (fd < 0) {
268                         errno = EINVAL;
269                         return -1;
270                 }
271 
272                 if ((1+fd) > base->nodes_count) {
273                         if (0 != rh_event_node_resize(base, fd+1))
274                                 return -1;
275                 }
276         
277                 event->node = base->nodes[fd];
278                 event->node->ep_event.data.fd = fd;
279         }
280 
281         event->fd = fd;
282         event->rh_events = events;
283         event->arg = arg;
284         event->cb = cb;
285         event->base = base;
286         event->timeout_time = time(NULL);
287         
288         return 0;
289 }
290 
291 int rh_event_signal_set (struct rh_event *event,
292                   struct rh_event_base *base,
293                   int sig,
294                   void (*cb)(int, short, void *),
295                   void *arg)
296 {
297         return rh_event_set (event, base, sig, RH_EVENT_SIGNAL, cb, arg);
298 }
299 
300 
301 int rh_event_del (struct rh_event *event)
302 {
303         struct rh_event_node    *node;
304         int                     ep_events;
305         short                   rh_events;
306         int                     ep_op;
307         
308         if (NULL == event || NULL == event->base)
309                 return -1;
310 
311         if (event->rh_events & RH_EVENT_SIGNAL) {
312                 if (!RH_EVENT_ISSET(event))
313                         return 0;
314 
315                 signal (event->fd, SIG_DFL);
316                 rh_event_signal[event->fd] = NULL;
317 
318                 return 0;
319 
320         }
321 
322         if (event->fd < 0 || (1+event->fd) > event->base->nodes_count)
323                 return -1;
324         
325 #if 0
326         printf ("%s(%p) fd: %d\n", __FUNCTION__, (void*)event, event->fd);
327 #endif
328         
329         node = event->node;
330         
331         if (event->rh_events & RH_EVENT_READ)
332                 node->read = NULL;
333         
334         if (event->rh_events & RH_EVENT_WRITE)
335                 node->write = NULL;
336         
337         if (RH_BIT_ISSETFULL(   event->rh_events,
338                                 RH_EVENT_DISPATCH|RH_EVENT_TIMEOUT))
339         {
340                 TAILQ_REMOVE(   &event->base->timeout_list,
341                                 event,
342                                 list);
343         }
344         
345         event->rh_events &= ~RH_EVENT_DISPATCH;
346 
347         rh_events = 0;
348 
349         if (node->read && (node->read->rh_events & RH_EVENT_DISPATCH))
350                 rh_events |= node->read->rh_events;
351         
352         if (node->write && (node->write->rh_events & RH_EVENT_DISPATCH))
353                 rh_events |= node->write->rh_events;
354                 
355         ep_events = rh_event_rh2ep (rh_events);
356 
357         if (0 == ep_events)
358                 ep_op = EPOLL_CTL_DEL;
359         else
360                 ep_op = EPOLL_CTL_MOD;
361 
362         node->ep_event.events = ep_events;
363 
364         //printf ("del: fd: %d ep_events: %d\n", event->fd, ep_events);
365                         
366         return epoll_ctl(event->base->fd, ep_op, event->fd, &node->ep_event);
367 }
368 
369 int rh_event_add (struct rh_event *event)
370 {
371         struct rh_event_node    *node;
372         short                   rh_events;
373         int                     ep_op;
374 
375 #if 0
376         printf ("%s(%p) fd: %d\n", __FUNCTION__, (void*)event, event->fd);
377 #endif
378 
379         if (NULL == event || NULL == event->base)
380                 return -1;
381         
382         if (RH_EVENT_ISSET(event))
383                 return 0;
384         
385         if (event->rh_events & RH_EVENT_SIGNAL) {
386                 if (SIG_ERR == signal (event->fd, rh_event_signal_handler))
387                         return -1;
388                 
389                 rh_event_signal[event->fd] = event;
390                 
391                 event->rh_events |= RH_EVENT_DISPATCH;
392 
393                 return 0;
394         }
395         
396         if (event->fd < 0 || (1+event->fd) > event->base->nodes_count)
397                 return -1;
398         
399         
400         node = event->node;
401 
402         event->rh_events |= RH_EVENT_DISPATCH;
403 
404         if (event->rh_events & RH_EVENT_TIMEOUT) {
405                 TAILQ_INSERT_TAIL(      &event->base->timeout_list,
406                                         event,
407                                         list);
408         }
409                 
410         if (event->rh_events & RH_EVENT_READ)
411                 node->read = event;
412         
413         if (event->rh_events & RH_EVENT_WRITE)
414                 node->write = event;
415 
416         rh_events = 0;
417         
418         if (node->read && (node->read->rh_events & RH_EVENT_DISPATCH))
419                 rh_events |= node->read->rh_events;
420         
421         if (node->write && (node->write->rh_events & RH_EVENT_DISPATCH))
422                 rh_events |= node->write->rh_events;
423 
424         if (0 == node->ep_event.events)
425                 ep_op = EPOLL_CTL_ADD;
426         else
427                 ep_op = EPOLL_CTL_MOD;
428                 
429         node->ep_event.events = rh_event_rh2ep (rh_events);
430         
431         return epoll_ctl(event->base->fd, ep_op, event->fd, &node->ep_event);
432 }


syntax highlighted by Code2HTML, v. 0.9.1