-#ifdef ASSERTIONS
- static int entry = 0;
-#endif
- SELECT_ARG_TYPE readfds, writefds, errfds, werrfds;
- struct timeval timeout, *tvptr;
- int ntries, maxfd, rc;
- long interval;
- time_t curtime;
- event_handle_t *eh, *nexteh;
- struct sigtabent *se;
- int event_wait_fired = 0;
- int see_event;
-
- event_debug(1, ("%s: event: loop: enter: dontblock=%d, qlength=%d, eh=%p\n",
- debug_prefix_time(NULL),
- dontblock, eventq.qlength, wait_eh));
-
- /*
- * If we have no events, we have nothing to do
- */
- if (eventq.qlength == 0)
- return 0;
-
- /*
- * We must not be entered twice
- */
- assert(++entry == 1);
-
- ntries = 0;
-
- /*
- * Save a copy of the current time once, to reduce syscall load
- * slightly.
- */
- curtime = time(NULL);
-
- do {
- if (debug_event >= 1) {
- event_debug(1, ("%s: event: loop: dontblock=%d, qlength=%d eh=%p\n",
- debug_prefix_time(NULL), dontblock, eventq.qlength,
- wait_eh));
- for (eh = eventq_first(eventq); eh != NULL; eh = eventq_next(eh)) {
- event_debug(1, ("%s: %p): %s data=%lu fn=%p arg=%p\n",
- debug_prefix_time(NULL), eh,
- event_type2str(eh->type), eh->data, eh->fn,
- eh->arg));
- }
- }
- /*
- * Set ourselves up with no timeout initially.
- */
- timeout.tv_sec = 0;
- timeout.tv_usec = 0;
-
- /*
- * If we can block, initially set the tvptr to NULL. If
- * we come across timeout events in the loop below, they
- * will set it to an appropriate buffer. If we don't
- * see any timeout events, then tvptr will remain NULL
- * and the select will properly block indefinately.
- *
- * If we can't block, set it to point to the timeout buf above.
- */
- if (dontblock)
- tvptr = &timeout;
- else
- tvptr = NULL;
-
- /*
- * Rebuild the select bitmasks each time.
- */
- FD_ZERO(&readfds);
- FD_ZERO(&writefds);
- FD_ZERO(&errfds);
- maxfd = 0;
-
- see_event = (wait_eh == (event_handle_t *)NULL);
- /*
- * Run through each event handle and setup the events.
- * We save our next pointer early in case we GC some dead
- * events.
- */
- for (eh = eventq_first(eventq); eh != NULL; eh = nexteh) {
- nexteh = eventq_next(eh);
-
- switch (eh->type) {
-
- /*
- * Read fds just get set into the select bitmask
- */
- case EV_READFD:
- FD_SET((int)eh->data, &readfds);
- FD_SET((int)eh->data, &errfds);
- maxfd = max(maxfd, (int)eh->data);
- see_event |= (eh == wait_eh);
- break;
-
- /*
- * Likewise with write fds
- */
- case EV_WRITEFD:
- FD_SET((int)eh->data, &writefds);
- FD_SET((int)eh->data, &errfds);
- maxfd = max(maxfd, (int)eh->data);
- see_event |= (eh == wait_eh);
- break;
-
- /*
- * Only set signals that aren't already set to avoid unnecessary
- * syscall overhead.
- */
- case EV_SIG:
- se = &sigtable[eh->data];
- see_event |= (eh == wait_eh);
-
- if (se->handle == eh)
- break;
-
- /* no previous handle */
- assert(se->handle == NULL);
- se->handle = eh;
- se->score = 0;
- /*@ignore@*/
- se->oldhandler = signal((int)eh->data, signal_handler);
- /*@end@*/
- break;
-
- /*
- * Compute the timeout for this select
- */
- case EV_TIME:
- /* if we're not supposed to block, then leave it at 0 */
- if (dontblock)
- break;
-
- if (eh->lastfired == -1)
- eh->lastfired = curtime;
-
- interval = (long)(eh->data - (curtime - eh->lastfired));
- if (interval < 0)
- interval = 0;
-
- if (tvptr != NULL)
- timeout.tv_sec = min(timeout.tv_sec, interval);
- else {
- /* this is the first timeout */
- tvptr = &timeout;
- timeout.tv_sec = interval;
- }
- see_event |= (eh == wait_eh);
- break;
-
- /*
- * Wait events are processed immediately by event_wakeup()
- */
- case EV_WAIT:
- see_event |= (eh == wait_eh);
- break;
-
- /*
- * Prune dead events
- */
- case EV_DEAD:
- eventq_remove(eh);
- puthandle(eh);
- break;
-
- default:
- assert(0);
- break;
- }
- }