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