1 /*        $NetBSD: eventlib.c,v 1.1.1.2 2012/09/09 16:08:00 christos Exp $      */
2 
3 /*
4  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (c) 1995-1999 by Internet Software Consortium
6  *
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.
10  *
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.
18  */
19 
20 /* eventlib.c - implement glue for the eventlib
21  * vix 09sep95 [initial]
22  */
23 
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
27 
28 #include "port_before.h"
29 #include "fd_setsize.h"
30 
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 */
37 
38 #include <errno.h>
39 #include <signal.h>
40 #include <stdarg.h>
41 #include <stdlib.h>
42 #include <unistd.h>
43 
44 #include <isc/eventlib.h>
45 #include <isc/assertions.h>
46 #include "eventlib_p.h"
47 
48 #include "port_after.h"
49 
50 int      __evOptMonoTime;
51 
52 #ifdef USE_POLL
53 #define   pselect Pselect
54 #endif /* USE_POLL */
55 
56 /* Forward. */
57 
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
63 
64 int    __evOptMonoTime;
65 
66 /* Public. */
67 
68 int
evCreate(evContext * opaqueCtx)69 evCreate(evContext *opaqueCtx) {
70           evContext_p *ctx;
71 
72           /* Make sure the memory heap is initialized. */
73           if (meminit(0, 0) < 0 && errno != EEXIST)
74                     return (-1);
75 
76           OKNEW(ctx);
77 
78           /* Global. */
79           ctx->cur = NULL;
80 
81           /* Debugging. */
82           ctx->debug = 0;
83           ctx->output = NULL;
84 
85           /* Connections. */
86           ctx->conns = NULL;
87           INIT_LIST(ctx->accepts);
88 
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
120 
121           /* Streams. */
122           ctx->streams = NULL;
123           ctx->strDone = NULL;
124           ctx->strLast = NULL;
125 
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);
134 
135           /* Waits. */
136           ctx->waitLists = NULL;
137           ctx->waitDone.first = ctx->waitDone.last = NULL;
138           ctx->waitDone.prev = ctx->waitDone.next = NULL;
139 
140           opaqueCtx->opaque = ctx;
141           return (0);
142 }
143 
144 void
evSetDebug(evContext opaqueCtx,int level,FILE * output)145 evSetDebug(evContext opaqueCtx, int level, FILE *output) {
146           evContext_p *ctx = opaqueCtx.opaque;
147 
148           ctx->debug = level;
149           ctx->output = output;
150 }
151 
152 int
evDestroy(evContext opaqueCtx)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;
158 
159           /* Connections. */
160           while (revs-- > 0 && ctx->conns != NULL) {
161                     evConnID id;
162 
163                     id.opaque = ctx->conns;
164                     (void) evCancelConn(opaqueCtx, id);
165           }
166           INSIST(revs >= 0);
167 
168           /* Streams. */
169           while (revs-- > 0 && ctx->streams != NULL) {
170                     evStreamID id;
171 
172                     id.opaque = ctx->streams;
173                     (void) evCancelRW(opaqueCtx, id);
174           }
175 
176           /* Files. */
177           while (revs-- > 0 && ctx->files != NULL) {
178                     evFileID id;
179 
180                     id.opaque = ctx->files;
181                     (void) evDeselectFD(opaqueCtx, id);
182           }
183           INSIST(revs >= 0);
184 
185           /* Timers. */
186           evDestroyTimers(ctx);
187 
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);
198                     }
199                     FREE(this_wl);
200           }
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);
206           }
207 
208           FREE(ctx);
209           return (0);
210 }
211 
212 int
evGetNext(evContext opaqueCtx,evEvent * opaqueEv,int options)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
222 
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);
227 
228           /* Get the time of day.  We'll do this again after select() blocks. */
229           ctx->lastEventTime = evNowTime();
230 
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);
240           }
241 
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);
252           }
253 
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);
264           }
265 
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;
277 
278                     /* Are there any events at all? */
279                     if ((options & EV_WAIT) != 0 && !nextTimer && ctx->fdMax == -1)
280                               EV_ERR(ENOENT);
281 
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;
299                     }
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);
309                     }
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
318                               /*
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.
323                                */
324 #endif /* USE_POLL */
325                               if (m == Timer) {
326                                         INSIST(tp == &t);
327                                         t = evSubTime(nextTime, ctx->lastEventTime);
328                               }
329 
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;
335 
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();
346 
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);
362                               }
363                               if (pselect_errno == EBADF) {
364                                         for (x = 0; x <= ctx->fdMax; x++) {
365                                                   struct stat sb;
366 
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",
374                                                                        x);
375                                         }
376                                         abort();
377                               }
378                               EV_ERR(pselect_errno);
379                     }
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
387           }
388           INSIST(nextTimer || ctx->fdCount);
389 
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);
394           }
395           if (nextTimer && timerPast) {
396                     OKNEW(new);
397                     new->type = Timer;
398                     new->u.timer.this = nextTimer;
399                     opaqueEv->opaque = new;
400                     return (0);
401           }
402 
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;
408 
409                     if (ctx->fdNext == NULL) {
410                               if (++x == 2) {
411                                         /*
412                                          * Hitting the end twice means that the last
413                                          * select() found some FD's which have since
414                                          * been deselected.
415                                          *
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().
426                                          */
427                                         ctx->fdCount = 0;
428                                         break;
429                               }
430                               ctx->fdNext = ctx->files;
431                     }
432                     fid = ctx->fdNext;
433                     ctx->fdNext = fid->next;
434 
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--;
448                               }
449                               if ((eventmask & EV_WRITE) != 0) {
450                                         FD_CLR(fd, &ctx->wrLast);
451                                         ctx->fdCount--;
452                               }
453                               if ((eventmask & EV_EXCEPT) != 0) {
454                                         FD_CLR(fd, &ctx->exLast);
455                                         ctx->fdCount--;
456                               }
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);
463                     }
464           }
465           if (ctx->fdCount < 0) {
466                     /*
467                      * select()'s count is off on a number of systems, and
468                      * can result in fdCount < 0.
469                      */
470                     evPrintf(ctx, 4, "fdCount < 0 (%d)\n", ctx->fdCount);
471                     ctx->fdCount = 0;
472           }
473 
474           /* We get here if the caller deselect()'s an FD. Gag me with a goto. */
475           goto again;
476 }
477 
478 int
evDispatch(evContext opaqueCtx,evEvent opaqueEv)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
487 
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;
496 
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;
509               }
510               case File: {
511                     evFile *this = ev->u.file.this;
512                     int eventmask = ev->u.file.eventmask;
513 
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;
522               }
523               case Stream: {
524                     evStream *this = ev->u.stream.this;
525 
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;
535               }
536               case Timer: {
537                     evTimer *this = ev->u.timer.this;
538 
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;
546               }
547               case Wait: {
548                     evWait *this = ev->u.wait.this;
549 
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;
558               }
559               case Null: {
560                     /* No work. */
561 #ifdef EVENTLIB_TIME_CHECKS
562                     func = NULL;
563 #endif
564                     break;
565               }
566               default: {
567                     abort();
568               }
569           }
570 #ifdef EVENTLIB_TIME_CHECKS
571           if (ctx->debug > 0) {
572                     interval = evSubTime(evNowTime(), start_time);
573                     /*
574                      * Complain if it took longer than 50 milliseconds.
575                      *
576                      * We call getuid() to make an easy to find mark in a kernel
577                      * trace.
578                      */
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);
584           }
585 #endif
586           ctx->cur = NULL;
587           evDrop(opaqueCtx, opaqueEv);
588           return (0);
589 }
590 
591 void
evDrop(evContext opaqueCtx,evEvent opaqueEv)592 evDrop(evContext opaqueCtx, evEvent opaqueEv) {
593           evContext_p *ctx = opaqueCtx.opaque;
594           evEvent_p *ev = opaqueEv.opaque;
595 
596           switch (ev->type) {
597               case Accept: {
598                     FREE(ev->u.accept.this);
599                     break;
600               }
601               case File: {
602                     /* No work. */
603                     break;
604               }
605               case Stream: {
606                     evStreamID id;
607 
608                     id.opaque = ev->u.stream.this;
609                     (void) evCancelRW(opaqueCtx, id);
610                     break;
611               }
612               case Timer: {
613                     evTimer *this = ev->u.timer.this;
614                     evTimerID opaque;
615 
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;
620                     }
621                     /*
622                      * Timer is still there.  Delete it if it has expired,
623                      * otherwise set it according to its next interval.
624                      */
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);
638                     }
639                     break;
640               }
641               case Wait: {
642                     FREE(ev->u.wait.this);
643                     break;
644               }
645               case Null: {
646                     /* No work. */
647                     break;
648               }
649               default: {
650                     abort();
651               }
652           }
653           FREE(ev);
654 }
655 
656 int
evMainLoop(evContext opaqueCtx)657 evMainLoop(evContext opaqueCtx) {
658           evEvent event;
659           int x;
660 
661           while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0)
662                     if ((x = evDispatch(opaqueCtx, event)) < 0)
663                               break;
664           return (x);
665 }
666 
667 int
evHighestFD(evContext opaqueCtx)668 evHighestFD(evContext opaqueCtx) {
669           evContext_p *ctx = opaqueCtx.opaque;
670 
671           return (ctx->highestFD);
672 }
673 
674 void
evPrintf(const evContext_p * ctx,int level,const char * fmt,...)675 evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) {
676           va_list ap;
677 
678           va_start(ap, fmt);
679           if (ctx->output != NULL && ctx->debug >= level) {
680                     vfprintf(ctx->output, fmt, ap);
681                     fflush(ctx->output);
682           }
683           va_end(ap);
684 }
685 
686 int
evSetOption(evContext * opaqueCtx,const char * option,int value)687 evSetOption(evContext *opaqueCtx, const char *option, int value) {
688           /* evContext_p *ctx = opaqueCtx->opaque; */
689 
690           UNUSED(opaqueCtx);
691           UNUSED(value);
692 #ifndef CLOCK_MONOTONIC
693           UNUSED(option);
694 #endif
695 
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);
706                     }
707           }
708 #endif
709           errno = ENOENT;
710           return (-1);
711 }
712 
713 int
evGetOption(evContext * opaqueCtx,const char * option,int * value)714 evGetOption(evContext *opaqueCtx, const char *option, int *value) {
715           /* evContext_p *ctx = opaqueCtx->opaque; */
716 
717           UNUSED(opaqueCtx);
718 #ifndef CLOCK_MONOTONIC
719           UNUSED(value);
720           UNUSED(option);
721 #endif
722 
723 #ifdef CLOCK_MONOTONIC
724           if (strcmp(option, "monotime") == 0) {
725                     if (opaqueCtx  != NULL)
726                               errno = EINVAL;
727                     *value = __evOptMonoTime;
728                     return (0);
729           }
730 #endif
731           errno = ENOENT;
732           return (-1);
733 }
734 
735 #if defined(NEED_PSELECT) || defined(USE_POLL)
736 /* XXX needs to move to the porting library. */
737 static int
pselect(int nfds,void * rfds,void * wfds,void * efds,struct timespec * tsp,const sigset_t * sigmask)738 pselect(int nfds, void *rfds, void *wfds, void *efds,
739           struct timespec *tsp,
740           const sigset_t *sigmask)
741 {
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;
750 
751           UNUSED(nfds);
752 #endif /* USE_POLL */
753 
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
767         /*
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.
771            */
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;
786           }
787           n = poll(fds, pnfds, polltimeout);
788           if (n > 0) {
789                     int     i, e;
790 
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++;
801                     }
802                     n = e;
803           }
804 #endif /* USE_POLL */
805           if (sigmask)
806                     sigprocmask(SIG_SETMASK, &sigs, NULL);
807           if (tsp)
808                     *tsp = evTimeSpec(tv);
809           return (n);
810 }
811 #endif
812 
813 #ifdef USE_POLL
814 int
evPollfdRealloc(evContext_p * ctx,int pollfd_chunk_size,int fd)815 evPollfdRealloc(evContext_p *ctx, int pollfd_chunk_size, int fd) {
816 
817           int     i, maxnfds;
818           void      *pollfds, *fdTable;
819 
820           if (fd < ctx->maxnfds)
821                     return (0);
822 
823           /* Don't allow ridiculously small values for pollfd_chunk_size */
824           if (pollfd_chunk_size < 20)
825                     pollfd_chunk_size = 20;
826 
827           maxnfds = (1 + (fd/pollfd_chunk_size)) * pollfd_chunk_size;
828 
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;
835 
836           if (pollfds == NULL || fdTable == NULL) {
837                     evPrintf(ctx, 2, "pollfd() realloc (%ld) failed\n",
838                                (long)maxnfds*sizeof(struct pollfd));
839                     return (-1);
840           }
841 
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;
846           }
847 
848           ctx->maxnfds = maxnfds;
849 
850           return (0);
851 }
852 
853 /* Find the appropriate 'events' or 'revents' field in the pollfds array */
854 short *
__fd_eventfield(int fd,__evEmulMask * maskp)855 __fd_eventfield(int fd, __evEmulMask *maskp) {
856 
857           evContext_p     *ctx = (evContext_p *)maskp->ctx;
858 
859           if (!maskp->result || maskp->type == EV_WASNONBLOCKING)
860                     return (&(ctx->pollfds[fd].events));
861           else
862                     return (&(ctx->pollfds[fd].revents));
863 }
864 
865 /* Translate to poll(2) event */
866 short
__poll_event(__evEmulMask * maskp)867 __poll_event(__evEmulMask *maskp) {
868 
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);
880           }
881 }
882 
883 /*
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.
887  */
888 void
__fd_clr(int fd,__evEmulMask * maskp)889 __fd_clr(int fd, __evEmulMask *maskp) {
890 
891           evContext_p     *ctx = maskp->ctx;
892 
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++;
904                     /*
905                      * Do we have a empty set of descriptors?
906                      */
907                     if (ctx->firstfd > ctx->fdMax) {
908                               ctx->fdMax = -1;
909                               ctx->firstfd = 0;
910                     }
911           }
912 }
913 
914 /*
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.
918  */
919 void
__fd_set(int fd,__evEmulMask * maskp)920 __fd_set(int fd, __evEmulMask *maskp) {
921 
922           evContext_p     *ctx = maskp->ctx;
923 
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;
931           }
932 }
933 #endif /* USE_POLL */
934 
935 /*! \file */
936