1 /***********************************************************************
2 *
3 * event.c
4 *
5 * Abstraction of select call into "event-handling" to make programming
6 * easier.
7 *
8 * Copyright (C) 2001-2003 Roaring Penguin Software Inc.
9 *
10 * This program may be distributed according to the terms of the GNU
11 * General Public License, version 2 or (at your option) any later version.
12 *
13 * Copyright (C) 2001 by Roaring Penguin Software Inc.
14 *
15 ***********************************************************************/
16
17 #include "event.h"
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22
23 static void DestroySelector(EventSelector *es);
24 static void DestroyHandler(EventHandler *eh);
25 static void DoPendingChanges(EventSelector *es);
26
27 #ifdef DEBUG_EVENT
28 #ifndef EVENT_USE_POLL
29 static void print_select_sets(char const *tag,
30 int maxfdp1, fd_set *rd, fd_set *wr);
31 #endif
32 #endif
33
34 #ifdef EVENT_USE_POLL
35 static struct pollfd *Pollfds = NULL;
36 static EventHandler **Fd_to_eh = NULL;
37 static int Size_of_pollfds = 0;
adjust_pollfds(int num)38 static int adjust_pollfds(int num) {
39 int new_size = Size_of_pollfds * 2;
40 if (new_size < num) new_size = num;
41 if (new_size < 16) new_size = 16;
42 Pollfds = realloc(Pollfds, (size_t) new_size * sizeof(struct pollfd));
43 if (!Pollfds) {
44 return -1;
45 }
46 Fd_to_eh = realloc(Fd_to_eh, (size_t) new_size * sizeof(EventHandler *));
47 if (!Fd_to_eh) {
48 return -1;
49 }
50 Size_of_pollfds = new_size;
51 return 0;
52 }
53 #endif
54
55
56 /**********************************************************************
57 * %FUNCTION: set_cloexec
58 * %ARGUMENTS:
59 * fd -- file descriptor
60 * %RETURNS:
61 * Nothing
62 * %DESCRIPTION:
63 * Sets the FD_CLOEXEC flag on descriptor
64 ***********************************************************************/
65 void
set_cloexec(int fd)66 set_cloexec(int fd)
67 {
68 int flags;
69 flags = fcntl(fd, F_GETFD);
70 if (flags >= 0) {
71 flags |= FD_CLOEXEC;
72 fcntl(fd, F_SETFD, flags);
73 }
74 }
75
76 /**********************************************************************
77 * %FUNCTION: set_nonblocking
78 * %ARGUMENTS:
79 * fd -- file descriptor
80 * %RETURNS:
81 * 0 on success, -1 on failure
82 * %DESCRIPTION:
83 * Sets the O_NONBLOCK flag on fd
84 ***********************************************************************/
85 int
set_nonblocking(int fd)86 set_nonblocking(int fd)
87 {
88 int flags = fcntl(fd, F_GETFL, 0);
89 if (flags < 0) return flags;
90 if (!(flags & O_NONBLOCK)) {
91 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
92 return -1;
93 }
94 }
95 return 0;
96 }
97
98 /**********************************************************************
99 * %FUNCTION: Event_CreateSelector
100 * %ARGUMENTS:
101 * None
102 * %RETURNS:
103 * A newly-allocated EventSelector, or NULL if out of memory.
104 * %DESCRIPTION:
105 * Creates a new EventSelector.
106 ***********************************************************************/
107 EventSelector *
Event_CreateSelector(void)108 Event_CreateSelector(void)
109 {
110 EventSelector *es = malloc(sizeof(EventSelector));
111 if (!es) return NULL;
112 es->handlers = NULL;
113 es->nestLevel = 0;
114 es->destroyPending = 0;
115 es->opsPending = 0;
116 EVENT_DEBUG(("CreateSelector() -> %p\n", (void *) es));
117 return es;
118 }
119
120 /**********************************************************************
121 * %FUNCTION: Event_DestroySelector
122 * %ARGUMENTS:
123 * es -- EventSelector to destroy
124 * %RETURNS:
125 * Nothing
126 * %DESCRIPTION:
127 * Destroys an EventSelector. Destruction may be delayed if we
128 * are in the HandleEvent function.
129 ***********************************************************************/
130 void
Event_DestroySelector(EventSelector * es)131 Event_DestroySelector(EventSelector *es)
132 {
133 if (es->nestLevel) {
134 es->destroyPending = 1;
135 es->opsPending = 1;
136 return;
137 }
138 DestroySelector(es);
139 }
140
141 #ifndef EVENT_USE_POLL
142 /**********************************************************************
143 * %FUNCTION: Event_HandleEventUsingSelect
144 * %ARGUMENTS:
145 * es -- EventSelector
146 * %RETURNS:
147 * 0 if OK, non-zero on error. errno is set appropriately.
148 * %DESCRIPTION:
149 * Handles a single event (uses select() to wait for an event.)
150 ***********************************************************************/
151 int
Event_HandleEventUsingSelect(EventSelector * es)152 Event_HandleEventUsingSelect(EventSelector *es)
153 {
154 fd_set readfds, writefds;
155 fd_set *rd, *wr;
156 unsigned int flags;
157
158 struct timeval abs_timeout, now;
159 struct timeval timeout;
160 struct timeval *tm;
161 EventHandler *eh;
162
163 int r = 0;
164 int errno_save = 0;
165 int foundTimeoutEvent = 0;
166 int foundReadEvent = 0;
167 int foundWriteEvent = 0;
168 int maxfd = -1;
169 int pastDue;
170
171 EVENT_DEBUG(("Enter Event_HandleEvent(es=%p)\n", (void *) es));
172
173 /* Silence stupid compiler warning */
174 abs_timeout.tv_sec = 0;
175 abs_timeout.tv_usec = 0;
176
177 /* Build the select sets */
178 FD_ZERO(&readfds);
179 FD_ZERO(&writefds);
180
181 eh = es->handlers;
182 for (eh=es->handlers; eh; eh=eh->next) {
183 if (eh->flags & EVENT_FLAG_DELETED) continue;
184 if (eh->flags & EVENT_FLAG_READABLE) {
185 foundReadEvent = 1;
186 FD_SET(eh->fd, &readfds);
187 if (eh->fd > maxfd) maxfd = eh->fd;
188 }
189 if (eh->flags & EVENT_FLAG_WRITEABLE) {
190 foundWriteEvent = 1;
191 FD_SET(eh->fd, &writefds);
192 if (eh->fd > maxfd) maxfd = eh->fd;
193 }
194 if (eh->flags & EVENT_TIMER_BITS) {
195 if (!foundTimeoutEvent) {
196 abs_timeout = eh->tmout;
197 foundTimeoutEvent = 1;
198 } else {
199 if (eh->tmout.tv_sec < abs_timeout.tv_sec ||
200 (eh->tmout.tv_sec == abs_timeout.tv_sec &&
201 eh->tmout.tv_usec < abs_timeout.tv_usec)) {
202 abs_timeout = eh->tmout;
203 }
204 }
205 }
206 }
207 if (foundReadEvent) {
208 rd = &readfds;
209 } else {
210 rd = NULL;
211 }
212 if (foundWriteEvent) {
213 wr = &writefds;
214 } else {
215 wr = NULL;
216 }
217
218 if (foundTimeoutEvent) {
219 gettimeofday(&now, NULL);
220
221 /* Convert absolute timeout to relative timeout for select */
222 timeout.tv_usec = abs_timeout.tv_usec - now.tv_usec;
223 timeout.tv_sec = abs_timeout.tv_sec - now.tv_sec;
224 if (timeout.tv_usec < 0) {
225 timeout.tv_usec += 1000000;
226 timeout.tv_sec--;
227 }
228 if (timeout.tv_sec < 0 ||
229 (timeout.tv_sec == 0 && timeout.tv_usec < 0)) {
230 timeout.tv_sec = 0;
231 timeout.tv_usec = 0;
232 }
233 tm = &timeout;
234 } else {
235 tm = NULL;
236 }
237
238 if (foundReadEvent || foundWriteEvent || foundTimeoutEvent) {
239 for(;;) {
240 #ifdef DEBUG_EVENT
241 print_select_sets("before", maxfd+1, rd, wr);
242 #endif
243 r = select(maxfd+1, rd, wr, NULL, tm);
244 #ifdef DEBUG_EVENT
245 print_select_sets("after ", maxfd+1, rd, wr);
246 #endif
247 if (r < 0) {
248 if (errno == EINTR) continue;
249 }
250 break;
251 }
252 }
253
254 if (foundTimeoutEvent) {
255 gettimeofday(&now, NULL);
256 }
257
258 errno_save = errno;
259 es->nestLevel++;
260
261 if (r >= 0) {
262 /* Call handlers */
263 for (eh=es->handlers; eh; eh=eh->next) {
264
265 /* Pending delete for this handler? Ignore it */
266 if (eh->flags & EVENT_FLAG_DELETED) continue;
267
268 flags = 0;
269 if ((eh->flags & EVENT_FLAG_READABLE) &&
270 FD_ISSET(eh->fd, &readfds)) {
271 flags |= EVENT_FLAG_READABLE;
272 }
273 if ((eh->flags & EVENT_FLAG_WRITEABLE) &&
274 FD_ISSET(eh->fd, &writefds)) {
275 flags |= EVENT_FLAG_WRITEABLE;
276 }
277 if (eh->flags & EVENT_TIMER_BITS) {
278 pastDue = (eh->tmout.tv_sec < now.tv_sec ||
279 (eh->tmout.tv_sec == now.tv_sec &&
280 eh->tmout.tv_usec <= now.tv_usec));
281 if (pastDue) {
282 flags |= EVENT_TIMER_BITS;
283 if (eh->flags & EVENT_FLAG_TIMER) {
284 /* Timer events are only called once */
285 es->opsPending = 1;
286 eh->flags |= EVENT_FLAG_DELETED;
287 }
288 }
289 }
290 /* Do callback */
291 if (flags) {
292 EVENT_DEBUG(("Enter callback: eh=%p flags=%u\n", eh, flags));
293 eh->fn(es, eh->fd, flags, eh->data);
294 EVENT_DEBUG(("Leave callback: eh=%p flags=%u\n", eh, flags));
295 }
296 }
297 }
298
299 es->nestLevel--;
300
301 if (!es->nestLevel && es->opsPending) {
302 DoPendingChanges(es);
303 }
304 errno = errno_save;
305 return r;
306 }
307 #endif
308
309 #ifdef EVENT_USE_POLL
310 /**********************************************************************
311 * %FUNCTION: Event_HandleEventUsingPoll
312 * %ARGUMENTS:
313 * es -- EventSelector
314 * %RETURNS:
315 * 0 if OK, non-zero on error. errno is set appropriately.
316 * %DESCRIPTION:
317 * Handles a single event (uses poll() to wait for an event.)
318 ***********************************************************************/
319 int
Event_HandleEventUsingPoll(EventSelector * es)320 Event_HandleEventUsingPoll(EventSelector *es)
321 {
322 struct timeval abs_timeout, now;
323 struct timeval timeout;
324 int tm;
325 EventHandler *eh;
326
327 int r = 0;
328 int errno_save = 0;
329 int foundTimeoutEvent = 0;
330 int pastDue;
331 int num_handlers = 0;
332 int nfds;
333 int i;
334
335 EVENT_DEBUG(("Enter Event_HandleEventUsingPoll(es=%p)\n", (void *) es));
336
337 /* Silence stupid compiler warning */
338 abs_timeout.tv_sec = 0;
339 abs_timeout.tv_usec = 0;
340
341 /* Build the pollfds array */
342 eh = es->handlers;
343 while(eh) {
344 num_handlers++;
345 eh = eh->next;
346 }
347
348 if (num_handlers > Size_of_pollfds) {
349 if (adjust_pollfds(num_handlers) < 0) {
350 return -1;
351 }
352 }
353
354 eh = es->handlers;
355 nfds = 0;
356 for (eh=es->handlers; eh; eh=eh->next) {
357 if (eh->flags & EVENT_FLAG_DELETED) continue;
358 eh->pollflags = 0;
359 if (eh->flags & (EVENT_FLAG_READABLE|EVENT_FLAG_WRITEABLE)) {
360 Pollfds[nfds].fd = eh->fd;
361 Pollfds[nfds].events = 0;
362 Fd_to_eh[nfds] = eh;
363 if (eh->flags & EVENT_FLAG_READABLE) {
364 Pollfds[nfds].events |= POLLIN;
365 }
366 if (eh->flags & EVENT_FLAG_WRITEABLE) {
367 Pollfds[nfds].events |= POLLOUT;
368 }
369 nfds++;
370 }
371 if (eh->flags & EVENT_TIMER_BITS) {
372 if (!foundTimeoutEvent) {
373 abs_timeout = eh->tmout;
374 foundTimeoutEvent = 1;
375 } else {
376 if (eh->tmout.tv_sec < abs_timeout.tv_sec ||
377 (eh->tmout.tv_sec == abs_timeout.tv_sec &&
378 eh->tmout.tv_usec < abs_timeout.tv_usec)) {
379 abs_timeout = eh->tmout;
380 }
381 }
382 }
383 }
384 if (foundTimeoutEvent) {
385 gettimeofday(&now, NULL);
386
387 /* Convert absolute timeout to relative timeout for poll */
388 timeout.tv_usec = abs_timeout.tv_usec - now.tv_usec;
389 timeout.tv_sec = abs_timeout.tv_sec - now.tv_sec;
390 if (timeout.tv_usec < 0) {
391 timeout.tv_usec += 1000000;
392 timeout.tv_sec--;
393 }
394 if (timeout.tv_sec < 0 ||
395 (timeout.tv_sec == 0 && timeout.tv_usec < 0)) {
396 timeout.tv_sec = 0;
397 timeout.tv_usec = 0;
398 }
399 tm = (timeout.tv_sec * 1000) + (timeout.tv_usec / 1000);
400 } else {
401 tm = -1;
402 }
403
404 if (nfds || foundTimeoutEvent) {
405 for(;;) {
406 r = poll(Pollfds, nfds, tm);
407 if (r < 0) {
408 if (errno == EINTR) continue;
409 }
410 break;
411 }
412 }
413
414 if (foundTimeoutEvent) {
415 gettimeofday(&now, NULL);
416 }
417
418 errno_save = errno;
419 es->nestLevel++;
420
421 if (r >= 0) {
422 /* Go through poll set and set pollflags */
423 for (i=0; i<nfds; i++) {
424 eh = Fd_to_eh[i];
425 if (Pollfds[i].revents & (POLLIN|POLLHUP)) {
426 if (eh->flags & EVENT_FLAG_READABLE) {
427 eh->pollflags |= EVENT_FLAG_READABLE;
428 }
429 }
430 if (Pollfds[i].revents & POLLOUT) {
431 if (eh->flags & EVENT_FLAG_WRITEABLE) {
432 eh->pollflags |= EVENT_FLAG_WRITEABLE;
433 }
434 }
435 }
436
437 /* Call handlers */
438 for (eh=es->handlers; eh; eh=eh->next) {
439 /* Pending delete for this handler? Ignore it */
440 if (eh->flags & EVENT_FLAG_DELETED) continue;
441
442 if (eh->flags & EVENT_TIMER_BITS) {
443 pastDue = (eh->tmout.tv_sec < now.tv_sec ||
444 (eh->tmout.tv_sec == now.tv_sec &&
445 eh->tmout.tv_usec <= now.tv_usec));
446 if (pastDue) {
447 eh->pollflags |= EVENT_TIMER_BITS;
448 if (eh->flags & EVENT_FLAG_TIMER) {
449 /* Timer events are only called once */
450 es->opsPending = 1;
451 eh->flags |= EVENT_FLAG_DELETED;
452 }
453 }
454 }
455 /* Do callback */
456 if (eh->pollflags) {
457 EVENT_DEBUG(("Enter callback: eh=%p flags=%u\n", eh, eh->pollflags));
458 eh->fn(es, eh->fd, eh->pollflags, eh->data);
459 EVENT_DEBUG(("Leave callback: eh=%p flags=%u\n", eh, eh->pollflags));
460 }
461 }
462 }
463
464 es->nestLevel--;
465
466 if (!es->nestLevel && es->opsPending) {
467 DoPendingChanges(es);
468 }
469 errno = errno_save;
470 return r;
471 }
472 #endif
473
474 /**********************************************************************
475 * %FUNCTION: Event_AddHandler
476 * %ARGUMENTS:
477 * es -- event selector
478 * fd -- file descriptor to watch
479 * flags -- combination of EVENT_FLAG_READABLE and EVENT_FLAG_WRITEABLE
480 * fn -- callback function to call when event is triggered
481 * data -- extra data to pass to callback function
482 * %RETURNS:
483 * A newly-allocated EventHandler, or NULL.
484 ***********************************************************************/
485 EventHandler *
Event_AddHandler(EventSelector * es,int fd,unsigned int flags,EventCallbackFunc fn,void * data)486 Event_AddHandler(EventSelector *es,
487 int fd,
488 unsigned int flags,
489 EventCallbackFunc fn,
490 void *data)
491 {
492 EventHandler *eh;
493
494 /* Specifically disable timer and deleted flags */
495 flags &= (~(EVENT_TIMER_BITS | EVENT_FLAG_DELETED));
496
497 /* Bad file descriptor */
498 if (fd < 0) {
499 errno = EBADF;
500 return NULL;
501 }
502
503 eh = malloc(sizeof(EventHandler));
504 if (!eh) return NULL;
505 eh->fd = fd;
506 eh->flags = flags;
507 eh->tmout.tv_usec = 0;
508 eh->tmout.tv_sec = 0;
509 eh->fn = fn;
510 eh->data = data;
511
512 /* Add immediately. This is safe even if we are in a handler. */
513 eh->next = es->handlers;
514 es->handlers = eh;
515
516 EVENT_DEBUG(("Event_AddHandler(es=%p, fd=%d, flags=%u) -> %p\n", es, fd, flags, eh));
517 return eh;
518 }
519
520 /**********************************************************************
521 * %FUNCTION: Event_AddHandlerWithTimeout
522 * %ARGUMENTS:
523 * es -- event selector
524 * fd -- file descriptor to watch
525 * flags -- combination of EVENT_FLAG_READABLE and EVENT_FLAG_WRITEABLE
526 * t -- Timeout after which to call handler, even if not readable/writable.
527 * If t.tv_sec < 0, calls normal Event_AddHandler with no timeout.
528 * fn -- callback function to call when event is triggered
529 * data -- extra data to pass to callback function
530 * %RETURNS:
531 * A newly-allocated EventHandler, or NULL.
532 ***********************************************************************/
533 EventHandler *
Event_AddHandlerWithTimeout(EventSelector * es,int fd,unsigned int flags,struct timeval t,EventCallbackFunc fn,void * data)534 Event_AddHandlerWithTimeout(EventSelector *es,
535 int fd,
536 unsigned int flags,
537 struct timeval t,
538 EventCallbackFunc fn,
539 void *data)
540 {
541 EventHandler *eh;
542 struct timeval now;
543
544 /* If timeout is negative, just do normal non-timing-out event */
545 if (t.tv_sec < 0 || t.tv_usec < 0) {
546 return Event_AddHandler(es, fd, flags, fn, data);
547 }
548
549 /* Specifically disable timer and deleted flags */
550 flags &= (~(EVENT_FLAG_TIMER | EVENT_FLAG_DELETED));
551 flags |= EVENT_FLAG_TIMEOUT;
552
553 /* Bad file descriptor? */
554 if (fd < 0) {
555 errno = EBADF;
556 return NULL;
557 }
558
559 /* Bad timeout? */
560 if (t.tv_usec >= 1000000) {
561 errno = EINVAL;
562 return NULL;
563 }
564
565 eh = malloc(sizeof(EventHandler));
566 if (!eh) return NULL;
567
568 /* Convert time interval to absolute time */
569 gettimeofday(&now, NULL);
570
571 t.tv_sec += now.tv_sec;
572 t.tv_usec += now.tv_usec;
573 if (t.tv_usec >= 1000000) {
574 t.tv_usec -= 1000000;
575 t.tv_sec++;
576 }
577
578 eh->fd = fd;
579 eh->flags = flags;
580 eh->tmout = t;
581 eh->fn = fn;
582 eh->data = data;
583
584 /* Add immediately. This is safe even if we are in a handler. */
585 eh->next = es->handlers;
586 es->handlers = eh;
587
588 EVENT_DEBUG(("Event_AddHandlerWithTimeout(es=%p, fd=%d, flags=%u, t=%d/%d) -> %p\n", es, fd, flags, t.tv_sec, t.tv_usec, eh));
589 return eh;
590 }
591
592
593 /**********************************************************************
594 * %FUNCTION: Event_AddTimerHandler
595 * %ARGUMENTS:
596 * es -- event selector
597 * t -- time interval after which to trigger event
598 * fn -- callback function to call when event is triggered
599 * data -- extra data to pass to callback function
600 * %RETURNS:
601 * A newly-allocated EventHandler, or NULL.
602 ***********************************************************************/
603 EventHandler *
Event_AddTimerHandler(EventSelector * es,struct timeval t,EventCallbackFunc fn,void * data)604 Event_AddTimerHandler(EventSelector *es,
605 struct timeval t,
606 EventCallbackFunc fn,
607 void *data)
608 {
609 EventHandler *eh;
610 struct timeval now;
611
612 /* Check time interval for validity */
613 if (t.tv_sec < 0 || t.tv_usec < 0 || t.tv_usec >= 1000000) {
614 errno = EINVAL;
615 return NULL;
616 }
617
618 eh = malloc(sizeof(EventHandler));
619 if (!eh) return NULL;
620
621 /* Convert time interval to absolute time */
622 gettimeofday(&now, NULL);
623
624 t.tv_sec += now.tv_sec;
625 t.tv_usec += now.tv_usec;
626 if (t.tv_usec >= 1000000) {
627 t.tv_usec -= 1000000;
628 t.tv_sec++;
629 }
630
631 eh->fd = -1;
632 eh->flags = EVENT_FLAG_TIMER;
633 eh->tmout = t;
634 eh->fn = fn;
635 eh->data = data;
636
637 /* Add immediately. This is safe even if we are in a handler. */
638 eh->next = es->handlers;
639 es->handlers = eh;
640
641 EVENT_DEBUG(("Event_AddTimerHandler(es=%p, t=%d/%d) -> %p\n", es, t.tv_sec,t.tv_usec, eh));
642 return eh;
643 }
644
645 /**********************************************************************
646 * %FUNCTION: Event_DelHandler
647 * %ARGUMENTS:
648 * es -- event selector
649 * eh -- event handler
650 * %RETURNS:
651 * 0 if OK, non-zero if there is an error
652 * %DESCRIPTION:
653 * Deletes the event handler eh
654 ***********************************************************************/
655 int
Event_DelHandler(EventSelector * es,EventHandler * eh)656 Event_DelHandler(EventSelector *es,
657 EventHandler *eh)
658 {
659 /* Scan the handlers list */
660 EventHandler *cur, *prev;
661 EVENT_DEBUG(("Event_DelHandler(es=%p, eh=%p)\n", es, eh));
662 for (cur=es->handlers, prev=NULL; cur; prev=cur, cur=cur->next) {
663 if (cur == eh) {
664 if (es->nestLevel) {
665 eh->flags |= EVENT_FLAG_DELETED;
666 es->opsPending = 1;
667 return 0;
668 } else {
669 if (prev) prev->next = cur->next;
670 else es->handlers = cur->next;
671
672 DestroyHandler(cur);
673 return 0;
674 }
675 }
676 }
677
678 /* Handler not found */
679 return 1;
680 }
681
682 /**********************************************************************
683 * %FUNCTION: DestroySelector
684 * %ARGUMENTS:
685 * es -- an event selector
686 * %RETURNS:
687 * Nothing
688 * %DESCRIPTION:
689 * Destroys selector and all associated handles.
690 ***********************************************************************/
691 static void
DestroySelector(EventSelector * es)692 DestroySelector(EventSelector *es)
693 {
694 EventHandler *cur, *next;
695 for (cur=es->handlers; cur; cur=next) {
696 next = cur->next;
697 DestroyHandler(cur);
698 }
699
700 free(es);
701 }
702
703 /**********************************************************************
704 * %FUNCTION: DestroyHandler
705 * %ARGUMENTS:
706 * eh -- an event handler
707 * %RETURNS:
708 * Nothing
709 * %DESCRIPTION:
710 * Destroys handler
711 ***********************************************************************/
712 static void
DestroyHandler(EventHandler * eh)713 DestroyHandler(EventHandler *eh)
714 {
715 EVENT_DEBUG(("DestroyHandler(eh=%p)\n", eh));
716 free(eh);
717 }
718
719 /**********************************************************************
720 * %FUNCTION: DoPendingChanges
721 * %ARGUMENTS:
722 * es -- an event selector
723 * %RETURNS:
724 * Nothing
725 * %DESCRIPTION:
726 * Makes all pending insertions and deletions happen.
727 ***********************************************************************/
728 static void
DoPendingChanges(EventSelector * es)729 DoPendingChanges(EventSelector *es)
730 {
731 EventHandler *cur, *prev, *next;
732
733 es->opsPending = 0;
734
735 /* If selector is to be deleted, do it and skip everything else */
736 if (es->destroyPending) {
737 DestroySelector(es);
738 return;
739 }
740
741 /* Do deletions */
742 cur = es->handlers;
743 prev = NULL;
744 while(cur) {
745 if (!(cur->flags & EVENT_FLAG_DELETED)) {
746 prev = cur;
747 cur = cur->next;
748 continue;
749 }
750
751 /* Unlink from list */
752 if (prev) {
753 prev->next = cur->next;
754 } else {
755 es->handlers = cur->next;
756 }
757 next = cur->next;
758 DestroyHandler(cur);
759 cur = next;
760 }
761 }
762
763 /**********************************************************************
764 * %FUNCTION: Event_GetCallback
765 * %ARGUMENTS:
766 * eh -- the event handler
767 * %RETURNS:
768 * The callback function
769 ***********************************************************************/
770 EventCallbackFunc
Event_GetCallback(EventHandler * eh)771 Event_GetCallback(EventHandler *eh)
772 {
773 return eh->fn;
774 }
775
776 /**********************************************************************
777 * %FUNCTION: Event_GetData
778 * %ARGUMENTS:
779 * eh -- the event handler
780 * %RETURNS:
781 * The "data" field.
782 ***********************************************************************/
783 void *
Event_GetData(EventHandler * eh)784 Event_GetData(EventHandler *eh)
785 {
786 return eh->data;
787 }
788
789 /**********************************************************************
790 * %FUNCTION: Event_SetCallbackAndData
791 * %ARGUMENTS:
792 * eh -- the event handler
793 * fn -- new callback function
794 * data -- new data value
795 * %RETURNS:
796 * Nothing
797 * %DESCRIPTION:
798 * Sets the callback function and data fields.
799 ***********************************************************************/
800 void
Event_SetCallbackAndData(EventHandler * eh,EventCallbackFunc fn,void * data)801 Event_SetCallbackAndData(EventHandler *eh,
802 EventCallbackFunc fn,
803 void *data)
804 {
805 eh->fn = fn;
806 eh->data = data;
807 }
808
809 #ifdef DEBUG_EVENT
810 #include <stdarg.h>
811 #include <stdio.h>
812 FILE *Event_DebugFP = NULL;
813 /**********************************************************************
814 * %FUNCTION: Event_DebugMsg
815 * %ARGUMENTS:
816 * fmt, ... -- format string
817 * %RETURNS:
818 * Nothing
819 * %DESCRIPTION:
820 * Writes a debug message to the debug file.
821 ***********************************************************************/
822 void
Event_DebugMsg(char const * fmt,...)823 Event_DebugMsg(char const *fmt, ...)
824 {
825 va_list ap;
826 struct timeval now;
827
828 if (!Event_DebugFP) return;
829
830 gettimeofday(&now, NULL);
831
832 fprintf(Event_DebugFP, "%03d.%03d ", (int) now.tv_sec % 1000,
833 (int) now.tv_usec / 1000);
834
835 va_start(ap, fmt);
836 vfprintf(Event_DebugFP, fmt, ap);
837 va_end(ap);
838 fflush(Event_DebugFP);
839 }
840
841 #ifndef EVENT_USE_POLL
842 static void
print_select_sets(char const * tag,int maxfdp1,fd_set * rd,fd_set * wr)843 print_select_sets(char const *tag, int maxfdp1, fd_set *rd, fd_set *wr)
844 {
845 int fd;
846 int done;
847
848 if (!Event_DebugFP) return;
849 fprintf(Event_DebugFP, "%s select: rd = [", tag);
850 done = 0;
851 if (rd) {
852 for (fd=0; fd<maxfdp1; fd++) {
853 if (FD_ISSET(fd, rd)) {
854 if (done) fprintf(Event_DebugFP, ", ");
855 done = 1;
856 fprintf(Event_DebugFP, "%d", fd);
857 }
858 }
859 }
860 fprintf(Event_DebugFP, "]\n%s select: wr = [", tag);
861 done = 0;
862 if (wr) {
863 for (fd=0; fd<maxfdp1; fd++) {
864 if (FD_ISSET(fd, wr)) {
865 if (done) fprintf(Event_DebugFP, ", ");
866 done = 1;
867 fprintf(Event_DebugFP, "%d", fd);
868 }
869 }
870 }
871 fprintf(Event_DebugFP, "]\n");
872 }
873 #endif
874 #endif
875
876 /**********************************************************************
877 * %FUNCTION: Event_EnableDebugging
878 * %ARGUMENTS:
879 * fname -- name of file to log debug messages to
880 * %RETURNS:
881 * 1 if debugging was enabled; 0 otherwise.
882 ***********************************************************************/
883 int
Event_EnableDebugging(char const * fname)884 Event_EnableDebugging(char const *fname)
885 {
886 #ifndef DEBUG_EVENT
887 return 0;
888 #else
889 Event_DebugFP = fopen(fname, "w");
890 return (Event_DebugFP != NULL);
891 #endif
892 }
893