Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / libbind / dist / isc / eventlib.c
blob1ed4184e7e59d2df17efec945e0517d69341da68
1 /* $NetBSD$ */
3 /*
4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (c) 1995-1999 by Internet Software Consortium
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 /* eventlib.c - implement glue for the eventlib
21 * vix 09sep95 [initial]
24 #if !defined(LINT) && !defined(CODECENTER)
25 static const char rcsid[] = "Id: eventlib.c,v 1.10 2006/03/09 23:57:56 marka Exp";
26 #endif
28 #include "port_before.h"
29 #include "fd_setsize.h"
31 #include <sys/types.h>
32 #include <sys/time.h>
33 #include <sys/stat.h>
34 #ifdef SOLARIS2
35 #include <limits.h>
36 #endif /* SOLARIS2 */
38 #include <errno.h>
39 #include <signal.h>
40 #include <stdarg.h>
41 #include <stdlib.h>
42 #include <unistd.h>
44 #include <isc/eventlib.h>
45 #include <isc/assertions.h>
46 #include "eventlib_p.h"
48 #include "port_after.h"
50 int __evOptMonoTime;
52 #ifdef USE_POLL
53 #define pselect Pselect
54 #endif /* USE_POLL */
56 /* Forward. */
58 #if defined(NEED_PSELECT) || defined(USE_POLL)
59 static int pselect(int, void *, void *, void *,
60 struct timespec *,
61 const sigset_t *);
62 #endif
64 int __evOptMonoTime;
66 /* Public. */
68 int
69 evCreate(evContext *opaqueCtx) {
70 evContext_p *ctx;
72 /* Make sure the memory heap is initialized. */
73 if (meminit(0, 0) < 0 && errno != EEXIST)
74 return (-1);
76 OKNEW(ctx);
78 /* Global. */
79 ctx->cur = NULL;
81 /* Debugging. */
82 ctx->debug = 0;
83 ctx->output = NULL;
85 /* Connections. */
86 ctx->conns = NULL;
87 INIT_LIST(ctx->accepts);
89 /* Files. */
90 ctx->files = NULL;
91 #ifdef USE_POLL
92 ctx->pollfds = NULL;
93 ctx->maxnfds = 0;
94 ctx->firstfd = 0;
95 emulMaskInit(ctx, rdLast, EV_READ, 1);
96 emulMaskInit(ctx, rdNext, EV_READ, 0);
97 emulMaskInit(ctx, wrLast, EV_WRITE, 1);
98 emulMaskInit(ctx, wrNext, EV_WRITE, 0);
99 emulMaskInit(ctx, exLast, EV_EXCEPT, 1);
100 emulMaskInit(ctx, exNext, EV_EXCEPT, 0);
101 emulMaskInit(ctx, nonblockBefore, EV_WASNONBLOCKING, 0);
102 #endif /* USE_POLL */
103 FD_ZERO(&ctx->rdNext);
104 FD_ZERO(&ctx->wrNext);
105 FD_ZERO(&ctx->exNext);
106 FD_ZERO(&ctx->nonblockBefore);
107 ctx->fdMax = -1;
108 ctx->fdNext = NULL;
109 ctx->fdCount = 0; /*%< Invalidate {rd,wr,ex}Last. */
110 #ifndef USE_POLL
111 ctx->highestFD = FD_SETSIZE - 1;
112 memset(ctx->fdTable, 0, sizeof ctx->fdTable);
113 #else
114 ctx->highestFD = INT_MAX / sizeof(struct pollfd);
115 ctx->fdTable = NULL;
116 #endif /* USE_POLL */
117 #ifdef EVENTLIB_TIME_CHECKS
118 ctx->lastFdCount = 0;
119 #endif
121 /* Streams. */
122 ctx->streams = NULL;
123 ctx->strDone = NULL;
124 ctx->strLast = NULL;
126 /* Timers. */
127 ctx->lastEventTime = evNowTime();
128 #ifdef EVENTLIB_TIME_CHECKS
129 ctx->lastSelectTime = ctx->lastEventTime;
130 #endif
131 ctx->timers = evCreateTimers(ctx);
132 if (ctx->timers == NULL)
133 return (-1);
135 /* Waits. */
136 ctx->waitLists = NULL;
137 ctx->waitDone.first = ctx->waitDone.last = NULL;
138 ctx->waitDone.prev = ctx->waitDone.next = NULL;
140 opaqueCtx->opaque = ctx;
141 return (0);
144 void
145 evSetDebug(evContext opaqueCtx, int level, FILE *output) {
146 evContext_p *ctx = opaqueCtx.opaque;
148 ctx->debug = level;
149 ctx->output = output;
153 evDestroy(evContext opaqueCtx) {
154 evContext_p *ctx = opaqueCtx.opaque;
155 int revs = 424242; /*%< Doug Adams. */
156 evWaitList *this_wl, *next_wl;
157 evWait *this_wait, *next_wait;
159 /* Connections. */
160 while (revs-- > 0 && ctx->conns != NULL) {
161 evConnID id;
163 id.opaque = ctx->conns;
164 (void) evCancelConn(opaqueCtx, id);
166 INSIST(revs >= 0);
168 /* Streams. */
169 while (revs-- > 0 && ctx->streams != NULL) {
170 evStreamID id;
172 id.opaque = ctx->streams;
173 (void) evCancelRW(opaqueCtx, id);
176 /* Files. */
177 while (revs-- > 0 && ctx->files != NULL) {
178 evFileID id;
180 id.opaque = ctx->files;
181 (void) evDeselectFD(opaqueCtx, id);
183 INSIST(revs >= 0);
185 /* Timers. */
186 evDestroyTimers(ctx);
188 /* Waits. */
189 for (this_wl = ctx->waitLists;
190 revs-- > 0 && this_wl != NULL;
191 this_wl = next_wl) {
192 next_wl = this_wl->next;
193 for (this_wait = this_wl->first;
194 revs-- > 0 && this_wait != NULL;
195 this_wait = next_wait) {
196 next_wait = this_wait->next;
197 FREE(this_wait);
199 FREE(this_wl);
201 for (this_wait = ctx->waitDone.first;
202 revs-- > 0 && this_wait != NULL;
203 this_wait = next_wait) {
204 next_wait = this_wait->next;
205 FREE(this_wait);
208 FREE(ctx);
209 return (0);
213 evGetNext(evContext opaqueCtx, evEvent *opaqueEv, int options) {
214 evContext_p *ctx = opaqueCtx.opaque;
215 struct timespec nextTime;
216 evTimer *nextTimer;
217 evEvent_p *new;
218 int x, pselect_errno, timerPast;
219 #ifdef EVENTLIB_TIME_CHECKS
220 struct timespec interval;
221 #endif
223 /* Ensure that exactly one of EV_POLL or EV_WAIT was specified. */
224 x = ((options & EV_POLL) != 0) + ((options & EV_WAIT) != 0);
225 if (x != 1)
226 EV_ERR(EINVAL);
228 /* Get the time of day. We'll do this again after select() blocks. */
229 ctx->lastEventTime = evNowTime();
231 again:
232 /* Finished accept()'s do not require a select(). */
233 if (!EMPTY(ctx->accepts)) {
234 OKNEW(new);
235 new->type = Accept;
236 new->u.accept.this = HEAD(ctx->accepts);
237 UNLINK(ctx->accepts, HEAD(ctx->accepts), link);
238 opaqueEv->opaque = new;
239 return (0);
242 /* Stream IO does not require a select(). */
243 if (ctx->strDone != NULL) {
244 OKNEW(new);
245 new->type = Stream;
246 new->u.stream.this = ctx->strDone;
247 ctx->strDone = ctx->strDone->nextDone;
248 if (ctx->strDone == NULL)
249 ctx->strLast = NULL;
250 opaqueEv->opaque = new;
251 return (0);
254 /* Waits do not require a select(). */
255 if (ctx->waitDone.first != NULL) {
256 OKNEW(new);
257 new->type = Wait;
258 new->u.wait.this = ctx->waitDone.first;
259 ctx->waitDone.first = ctx->waitDone.first->next;
260 if (ctx->waitDone.first == NULL)
261 ctx->waitDone.last = NULL;
262 opaqueEv->opaque = new;
263 return (0);
266 /* Get the status and content of the next timer. */
267 if ((nextTimer = heap_element(ctx->timers, 1)) != NULL) {
268 nextTime = nextTimer->due;
269 timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
270 } else
271 timerPast = 0; /*%< Make gcc happy. */
272 evPrintf(ctx, 9, "evGetNext: fdCount %d\n", ctx->fdCount);
273 if (ctx->fdCount == 0) {
274 static const struct timespec NoTime = {0, 0L};
275 enum { JustPoll, Block, Timer } m;
276 struct timespec t, *tp;
278 /* Are there any events at all? */
279 if ((options & EV_WAIT) != 0 && !nextTimer && ctx->fdMax == -1)
280 EV_ERR(ENOENT);
282 /* Figure out what select()'s timeout parameter should be. */
283 if ((options & EV_POLL) != 0) {
284 m = JustPoll;
285 t = NoTime;
286 tp = &t;
287 } else if (nextTimer == NULL) {
288 m = Block;
289 /* ``t'' unused. */
290 tp = NULL;
291 } else if (timerPast) {
292 m = JustPoll;
293 t = NoTime;
294 tp = &t;
295 } else {
296 m = Timer;
297 /* ``t'' filled in later. */
298 tp = &t;
300 #ifdef EVENTLIB_TIME_CHECKS
301 if (ctx->debug > 0) {
302 interval = evSubTime(ctx->lastEventTime,
303 ctx->lastSelectTime);
304 if (interval.tv_sec > 0 || interval.tv_nsec > 0)
305 evPrintf(ctx, 1,
306 "time between pselect() %u.%09u count %d\n",
307 interval.tv_sec, interval.tv_nsec,
308 ctx->lastFdCount);
310 #endif
311 do {
312 #ifndef USE_POLL
313 /* XXX need to copy only the bits we are using. */
314 ctx->rdLast = ctx->rdNext;
315 ctx->wrLast = ctx->wrNext;
316 ctx->exLast = ctx->exNext;
317 #else
319 * The pollfd structure uses separate fields for
320 * the input and output events (corresponding to
321 * the ??Next and ??Last fd sets), so there's no
322 * need to copy one to the other.
324 #endif /* USE_POLL */
325 if (m == Timer) {
326 INSIST(tp == &t);
327 t = evSubTime(nextTime, ctx->lastEventTime);
330 /* XXX should predict system's earliness and adjust. */
331 x = pselect(ctx->fdMax+1,
332 &ctx->rdLast, &ctx->wrLast, &ctx->exLast,
333 tp, NULL);
334 pselect_errno = errno;
336 #ifndef USE_POLL
337 evPrintf(ctx, 4, "select() returns %d (err: %s)\n",
338 x, (x == -1) ? strerror(errno) : "none");
339 #else
340 evPrintf(ctx, 4, "poll() returns %d (err: %s)\n",
341 x, (x == -1) ? strerror(errno) : "none");
342 #endif /* USE_POLL */
343 /* Anything but a poll can change the time. */
344 if (m != JustPoll)
345 ctx->lastEventTime = evNowTime();
347 /* Select() likes to finish about 10ms early. */
348 } while (x == 0 && m == Timer &&
349 evCmpTime(ctx->lastEventTime, nextTime) < 0);
350 #ifdef EVENTLIB_TIME_CHECKS
351 ctx->lastSelectTime = ctx->lastEventTime;
352 #endif
353 if (x < 0) {
354 if (pselect_errno == EINTR) {
355 if ((options & EV_NULL) != 0)
356 goto again;
357 OKNEW(new);
358 new->type = Null;
359 /* No data. */
360 opaqueEv->opaque = new;
361 return (0);
363 if (pselect_errno == EBADF) {
364 for (x = 0; x <= ctx->fdMax; x++) {
365 struct stat sb;
367 if (FD_ISSET(x, &ctx->rdNext) == 0 &&
368 FD_ISSET(x, &ctx->wrNext) == 0 &&
369 FD_ISSET(x, &ctx->exNext) == 0)
370 continue;
371 if (fstat(x, &sb) == -1 &&
372 errno == EBADF)
373 evPrintf(ctx, 1, "EBADF: %d\n",
376 abort();
378 EV_ERR(pselect_errno);
380 if (x == 0 && (nextTimer == NULL || !timerPast) &&
381 (options & EV_POLL))
382 EV_ERR(EWOULDBLOCK);
383 ctx->fdCount = x;
384 #ifdef EVENTLIB_TIME_CHECKS
385 ctx->lastFdCount = x;
386 #endif
388 INSIST(nextTimer || ctx->fdCount);
390 /* Timers go first since we'd like them to be accurate. */
391 if (nextTimer && !timerPast) {
392 /* Has anything happened since we blocked? */
393 timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
395 if (nextTimer && timerPast) {
396 OKNEW(new);
397 new->type = Timer;
398 new->u.timer.this = nextTimer;
399 opaqueEv->opaque = new;
400 return (0);
403 /* No timers, so there should be a ready file descriptor. */
404 x = 0;
405 while (ctx->fdCount > 0) {
406 evFile *fid;
407 int fd, eventmask;
409 if (ctx->fdNext == NULL) {
410 if (++x == 2) {
412 * Hitting the end twice means that the last
413 * select() found some FD's which have since
414 * been deselected.
416 * On some systems, the count returned by
417 * selects is the total number of bits in
418 * all masks that are set, and on others it's
419 * the number of fd's that have some bit set,
420 * and on others, it's just broken. We
421 * always assume that it's the number of
422 * bits set in all masks, because that's what
423 * the man page says it should do, and
424 * the worst that can happen is we do an
425 * extra select().
427 ctx->fdCount = 0;
428 break;
430 ctx->fdNext = ctx->files;
432 fid = ctx->fdNext;
433 ctx->fdNext = fid->next;
435 fd = fid->fd;
436 eventmask = 0;
437 if (FD_ISSET(fd, &ctx->rdLast))
438 eventmask |= EV_READ;
439 if (FD_ISSET(fd, &ctx->wrLast))
440 eventmask |= EV_WRITE;
441 if (FD_ISSET(fd, &ctx->exLast))
442 eventmask |= EV_EXCEPT;
443 eventmask &= fid->eventmask;
444 if (eventmask != 0) {
445 if ((eventmask & EV_READ) != 0) {
446 FD_CLR(fd, &ctx->rdLast);
447 ctx->fdCount--;
449 if ((eventmask & EV_WRITE) != 0) {
450 FD_CLR(fd, &ctx->wrLast);
451 ctx->fdCount--;
453 if ((eventmask & EV_EXCEPT) != 0) {
454 FD_CLR(fd, &ctx->exLast);
455 ctx->fdCount--;
457 OKNEW(new);
458 new->type = File;
459 new->u.file.this = fid;
460 new->u.file.eventmask = eventmask;
461 opaqueEv->opaque = new;
462 return (0);
465 if (ctx->fdCount < 0) {
467 * select()'s count is off on a number of systems, and
468 * can result in fdCount < 0.
470 evPrintf(ctx, 4, "fdCount < 0 (%d)\n", ctx->fdCount);
471 ctx->fdCount = 0;
474 /* We get here if the caller deselect()'s an FD. Gag me with a goto. */
475 goto again;
479 evDispatch(evContext opaqueCtx, evEvent opaqueEv) {
480 evContext_p *ctx = opaqueCtx.opaque;
481 evEvent_p *ev = opaqueEv.opaque;
482 #ifdef EVENTLIB_TIME_CHECKS
483 void *func;
484 struct timespec start_time;
485 struct timespec interval;
486 #endif
488 #ifdef EVENTLIB_TIME_CHECKS
489 if (ctx->debug > 0)
490 start_time = evNowTime();
491 #endif
492 ctx->cur = ev;
493 switch (ev->type) {
494 case Accept: {
495 evAccept *this = ev->u.accept.this;
497 evPrintf(ctx, 5,
498 "Dispatch.Accept: fd %d -> %d, func %p, uap %p\n",
499 this->conn->fd, this->fd,
500 this->conn->func, this->conn->uap);
501 errno = this->ioErrno;
502 (this->conn->func)(opaqueCtx, this->conn->uap, this->fd,
503 &this->la, this->lalen,
504 &this->ra, this->ralen);
505 #ifdef EVENTLIB_TIME_CHECKS
506 func = this->conn->func;
507 #endif
508 break;
510 case File: {
511 evFile *this = ev->u.file.this;
512 int eventmask = ev->u.file.eventmask;
514 evPrintf(ctx, 5,
515 "Dispatch.File: fd %d, mask 0x%x, func %p, uap %p\n",
516 this->fd, this->eventmask, this->func, this->uap);
517 (this->func)(opaqueCtx, this->uap, this->fd, eventmask);
518 #ifdef EVENTLIB_TIME_CHECKS
519 func = this->func;
520 #endif
521 break;
523 case Stream: {
524 evStream *this = ev->u.stream.this;
526 evPrintf(ctx, 5,
527 "Dispatch.Stream: fd %d, func %p, uap %p\n",
528 this->fd, this->func, this->uap);
529 errno = this->ioErrno;
530 (this->func)(opaqueCtx, this->uap, this->fd, this->ioDone);
531 #ifdef EVENTLIB_TIME_CHECKS
532 func = this->func;
533 #endif
534 break;
536 case Timer: {
537 evTimer *this = ev->u.timer.this;
539 evPrintf(ctx, 5, "Dispatch.Timer: func %p, uap %p\n",
540 this->func, this->uap);
541 (this->func)(opaqueCtx, this->uap, this->due, this->inter);
542 #ifdef EVENTLIB_TIME_CHECKS
543 func = this->func;
544 #endif
545 break;
547 case Wait: {
548 evWait *this = ev->u.wait.this;
550 evPrintf(ctx, 5,
551 "Dispatch.Wait: tag %p, func %p, uap %p\n",
552 this->tag, this->func, this->uap);
553 (this->func)(opaqueCtx, this->uap, this->tag);
554 #ifdef EVENTLIB_TIME_CHECKS
555 func = this->func;
556 #endif
557 break;
559 case Null: {
560 /* No work. */
561 #ifdef EVENTLIB_TIME_CHECKS
562 func = NULL;
563 #endif
564 break;
566 default: {
567 abort();
570 #ifdef EVENTLIB_TIME_CHECKS
571 if (ctx->debug > 0) {
572 interval = evSubTime(evNowTime(), start_time);
574 * Complain if it took longer than 50 milliseconds.
576 * We call getuid() to make an easy to find mark in a kernel
577 * trace.
579 if (interval.tv_sec > 0 || interval.tv_nsec > 50000000)
580 evPrintf(ctx, 1,
581 "dispatch interval %u.%09u uid %d type %d func %p\n",
582 interval.tv_sec, interval.tv_nsec,
583 getuid(), ev->type, func);
585 #endif
586 ctx->cur = NULL;
587 evDrop(opaqueCtx, opaqueEv);
588 return (0);
591 void
592 evDrop(evContext opaqueCtx, evEvent opaqueEv) {
593 evContext_p *ctx = opaqueCtx.opaque;
594 evEvent_p *ev = opaqueEv.opaque;
596 switch (ev->type) {
597 case Accept: {
598 FREE(ev->u.accept.this);
599 break;
601 case File: {
602 /* No work. */
603 break;
605 case Stream: {
606 evStreamID id;
608 id.opaque = ev->u.stream.this;
609 (void) evCancelRW(opaqueCtx, id);
610 break;
612 case Timer: {
613 evTimer *this = ev->u.timer.this;
614 evTimerID opaque;
616 /* Check to see whether the user func cleared the timer. */
617 if (heap_element(ctx->timers, this->index) != this) {
618 evPrintf(ctx, 5, "Dispatch.Timer: timer rm'd?\n");
619 break;
622 * Timer is still there. Delete it if it has expired,
623 * otherwise set it according to its next interval.
625 if (this->inter.tv_sec == (time_t)0 &&
626 this->inter.tv_nsec == 0L) {
627 opaque.opaque = this;
628 (void) evClearTimer(opaqueCtx, opaque);
629 } else {
630 opaque.opaque = this;
631 (void) evResetTimer(opaqueCtx, opaque, this->func,
632 this->uap,
633 evAddTime((this->mode & EV_TMR_RATE) ?
634 this->due :
635 ctx->lastEventTime,
636 this->inter),
637 this->inter);
639 break;
641 case Wait: {
642 FREE(ev->u.wait.this);
643 break;
645 case Null: {
646 /* No work. */
647 break;
649 default: {
650 abort();
653 FREE(ev);
657 evMainLoop(evContext opaqueCtx) {
658 evEvent event;
659 int x;
661 while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0)
662 if ((x = evDispatch(opaqueCtx, event)) < 0)
663 break;
664 return (x);
668 evHighestFD(evContext opaqueCtx) {
669 evContext_p *ctx = opaqueCtx.opaque;
671 return (ctx->highestFD);
674 void
675 evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) {
676 va_list ap;
678 va_start(ap, fmt);
679 if (ctx->output != NULL && ctx->debug >= level) {
680 vfprintf(ctx->output, fmt, ap);
681 fflush(ctx->output);
683 va_end(ap);
687 evSetOption(evContext *opaqueCtx, const char *option, int value) {
688 /* evContext_p *ctx = opaqueCtx->opaque; */
690 UNUSED(opaqueCtx);
691 UNUSED(value);
692 #ifndef CLOCK_MONOTONIC
693 UNUSED(option);
694 #endif
696 #ifdef CLOCK_MONOTONIC
697 if (strcmp(option, "monotime") == 0) {
698 if (opaqueCtx != NULL)
699 errno = EINVAL;
700 if (value == 0 || value == 1) {
701 __evOptMonoTime = value;
702 return (0);
703 } else {
704 errno = EINVAL;
705 return (-1);
708 #endif
709 errno = ENOENT;
710 return (-1);
714 evGetOption(evContext *opaqueCtx, const char *option, int *value) {
715 /* evContext_p *ctx = opaqueCtx->opaque; */
717 UNUSED(opaqueCtx);
718 #ifndef CLOCK_MONOTONIC
719 UNUSED(value);
720 UNUSED(option);
721 #endif
723 #ifdef CLOCK_MONOTONIC
724 if (strcmp(option, "monotime") == 0) {
725 if (opaqueCtx != NULL)
726 errno = EINVAL;
727 *value = __evOptMonoTime;
728 return (0);
730 #endif
731 errno = ENOENT;
732 return (-1);
735 #if defined(NEED_PSELECT) || defined(USE_POLL)
736 /* XXX needs to move to the porting library. */
737 static int
738 pselect(int nfds, void *rfds, void *wfds, void *efds,
739 struct timespec *tsp,
740 const sigset_t *sigmask)
742 struct timeval tv, *tvp;
743 sigset_t sigs;
744 int n;
745 #ifdef USE_POLL
746 int polltimeout = INFTIM;
747 evContext_p *ctx;
748 struct pollfd *fds;
749 nfds_t pnfds;
751 UNUSED(nfds);
752 #endif /* USE_POLL */
754 if (tsp) {
755 tvp = &tv;
756 tv = evTimeVal(*tsp);
757 #ifdef USE_POLL
758 polltimeout = 1000 * tv.tv_sec + tv.tv_usec / 1000;
759 #endif /* USE_POLL */
760 } else
761 tvp = NULL;
762 if (sigmask)
763 sigprocmask(SIG_SETMASK, sigmask, &sigs);
764 #ifndef USE_POLL
765 n = select(nfds, rfds, wfds, efds, tvp);
766 #else
768 * rfds, wfds, and efds should all be from the same evContext_p,
769 * so any of them will do. If they're all NULL, the caller is
770 * presumably calling us to block.
772 if (rfds != NULL)
773 ctx = ((__evEmulMask *)rfds)->ctx;
774 else if (wfds != NULL)
775 ctx = ((__evEmulMask *)wfds)->ctx;
776 else if (efds != NULL)
777 ctx = ((__evEmulMask *)efds)->ctx;
778 else
779 ctx = NULL;
780 if (ctx != NULL && ctx->fdMax != -1) {
781 fds = &(ctx->pollfds[ctx->firstfd]);
782 pnfds = ctx->fdMax - ctx->firstfd + 1;
783 } else {
784 fds = NULL;
785 pnfds = 0;
787 n = poll(fds, pnfds, polltimeout);
788 if (n > 0) {
789 int i, e;
791 INSIST(ctx != NULL);
792 for (e = 0, i = ctx->firstfd; i <= ctx->fdMax; i++) {
793 if (ctx->pollfds[i].fd < 0)
794 continue;
795 if (FD_ISSET(i, &ctx->rdLast))
796 e++;
797 if (FD_ISSET(i, &ctx->wrLast))
798 e++;
799 if (FD_ISSET(i, &ctx->exLast))
800 e++;
802 n = e;
804 #endif /* USE_POLL */
805 if (sigmask)
806 sigprocmask(SIG_SETMASK, &sigs, NULL);
807 if (tsp)
808 *tsp = evTimeSpec(tv);
809 return (n);
811 #endif
813 #ifdef USE_POLL
815 evPollfdRealloc(evContext_p *ctx, int pollfd_chunk_size, int fd) {
817 int i, maxnfds;
818 void *pollfds, *fdTable;
820 if (fd < ctx->maxnfds)
821 return (0);
823 /* Don't allow ridiculously small values for pollfd_chunk_size */
824 if (pollfd_chunk_size < 20)
825 pollfd_chunk_size = 20;
827 maxnfds = (1 + (fd/pollfd_chunk_size)) * pollfd_chunk_size;
829 pollfds = realloc(ctx->pollfds, maxnfds * sizeof(*ctx->pollfds));
830 if (pollfds != NULL)
831 ctx->pollfds = pollfds;
832 fdTable = realloc(ctx->fdTable, maxnfds * sizeof(*ctx->fdTable));
833 if (fdTable != NULL)
834 ctx->fdTable = fdTable;
836 if (pollfds == NULL || fdTable == NULL) {
837 evPrintf(ctx, 2, "pollfd() realloc (%ld) failed\n",
838 (long)maxnfds*sizeof(struct pollfd));
839 return (-1);
842 for (i = ctx->maxnfds; i < maxnfds; i++) {
843 ctx->pollfds[i].fd = -1;
844 ctx->pollfds[i].events = 0;
845 ctx->fdTable[i] = 0;
848 ctx->maxnfds = maxnfds;
850 return (0);
853 /* Find the appropriate 'events' or 'revents' field in the pollfds array */
854 short *
855 __fd_eventfield(int fd, __evEmulMask *maskp) {
857 evContext_p *ctx = (evContext_p *)maskp->ctx;
859 if (!maskp->result || maskp->type == EV_WASNONBLOCKING)
860 return (&(ctx->pollfds[fd].events));
861 else
862 return (&(ctx->pollfds[fd].revents));
865 /* Translate to poll(2) event */
866 short
867 __poll_event(__evEmulMask *maskp) {
869 switch ((maskp)->type) {
870 case EV_READ:
871 return (POLLRDNORM);
872 case EV_WRITE:
873 return (POLLWRNORM);
874 case EV_EXCEPT:
875 return (POLLRDBAND | POLLPRI | POLLWRBAND);
876 case EV_WASNONBLOCKING:
877 return (POLLHUP);
878 default:
879 return (0);
884 * Clear the events corresponding to the specified mask. If this leaves
885 * the events mask empty (apart from the POLLHUP bit), set the fd field
886 * to -1 so that poll(2) will ignore this fd.
888 void
889 __fd_clr(int fd, __evEmulMask *maskp) {
891 evContext_p *ctx = maskp->ctx;
893 *__fd_eventfield(fd, maskp) &= ~__poll_event(maskp);
894 if ((ctx->pollfds[fd].events & ~POLLHUP) == 0) {
895 ctx->pollfds[fd].fd = -1;
896 if (fd == ctx->fdMax)
897 while (ctx->fdMax > ctx->firstfd &&
898 ctx->pollfds[ctx->fdMax].fd < 0)
899 ctx->fdMax--;
900 if (fd == ctx->firstfd)
901 while (ctx->firstfd <= ctx->fdMax &&
902 ctx->pollfds[ctx->firstfd].fd < 0)
903 ctx->firstfd++;
905 * Do we have a empty set of descriptors?
907 if (ctx->firstfd > ctx->fdMax) {
908 ctx->fdMax = -1;
909 ctx->firstfd = 0;
915 * Set the events bit(s) corresponding to the specified mask. If the events
916 * field has any other bits than POLLHUP set, also set the fd field so that
917 * poll(2) will watch this fd.
919 void
920 __fd_set(int fd, __evEmulMask *maskp) {
922 evContext_p *ctx = maskp->ctx;
924 *__fd_eventfield(fd, maskp) |= __poll_event(maskp);
925 if ((ctx->pollfds[fd].events & ~POLLHUP) != 0) {
926 ctx->pollfds[fd].fd = fd;
927 if (fd < ctx->firstfd || ctx->fdMax == -1)
928 ctx->firstfd = fd;
929 if (fd > ctx->fdMax)
930 ctx->fdMax = fd;
933 #endif /* USE_POLL */
935 /*! \file */