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