17c478bd9Sstevel@tonic-gate /* 2*9525b14bSRao Shoaib * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 37c478bd9Sstevel@tonic-gate * Copyright (c) 1995-1999 by Internet Software Consortium 47c478bd9Sstevel@tonic-gate * 57c478bd9Sstevel@tonic-gate * Permission to use, copy, modify, and distribute this software for any 67c478bd9Sstevel@tonic-gate * purpose with or without fee is hereby granted, provided that the above 77c478bd9Sstevel@tonic-gate * copyright notice and this permission notice appear in all copies. 87c478bd9Sstevel@tonic-gate * 9*9525b14bSRao Shoaib * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10*9525b14bSRao Shoaib * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11*9525b14bSRao Shoaib * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12*9525b14bSRao Shoaib * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13*9525b14bSRao Shoaib * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14*9525b14bSRao Shoaib * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15*9525b14bSRao Shoaib * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 167c478bd9Sstevel@tonic-gate */ 177c478bd9Sstevel@tonic-gate 187c478bd9Sstevel@tonic-gate /* eventlib.c - implement glue for the eventlib 197c478bd9Sstevel@tonic-gate * vix 09sep95 [initial] 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate 227c478bd9Sstevel@tonic-gate #if !defined(LINT) && !defined(CODECENTER) 23*9525b14bSRao Shoaib static const char rcsid[] = "$Id: eventlib.c,v 1.10 2006/03/09 23:57:56 marka Exp $"; 247c478bd9Sstevel@tonic-gate #endif 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include "port_before.h" 277c478bd9Sstevel@tonic-gate #include "fd_setsize.h" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/time.h> 317c478bd9Sstevel@tonic-gate #include <sys/stat.h> 32*9525b14bSRao Shoaib #ifdef SOLARIS2 337c478bd9Sstevel@tonic-gate #include <limits.h> 34*9525b14bSRao Shoaib #endif /* SOLARIS2 */ 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate #include <errno.h> 377c478bd9Sstevel@tonic-gate #include <signal.h> 387c478bd9Sstevel@tonic-gate #include <stdarg.h> 397c478bd9Sstevel@tonic-gate #include <stdlib.h> 407c478bd9Sstevel@tonic-gate #include <unistd.h> 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include <isc/eventlib.h> 437c478bd9Sstevel@tonic-gate #include <isc/assertions.h> 447c478bd9Sstevel@tonic-gate #include "eventlib_p.h" 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate #include "port_after.h" 477c478bd9Sstevel@tonic-gate 48*9525b14bSRao Shoaib int __evOptMonoTime; 49*9525b14bSRao Shoaib 50*9525b14bSRao Shoaib #ifdef USE_POLL 517c478bd9Sstevel@tonic-gate #define pselect Pselect 52*9525b14bSRao Shoaib #endif /* USE_POLL */ 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate /* Forward. */ 557c478bd9Sstevel@tonic-gate 56*9525b14bSRao Shoaib #if defined(NEED_PSELECT) || defined(USE_POLL) 577c478bd9Sstevel@tonic-gate static int pselect(int, void *, void *, void *, 587c478bd9Sstevel@tonic-gate struct timespec *, 597c478bd9Sstevel@tonic-gate const sigset_t *); 607c478bd9Sstevel@tonic-gate #endif 617c478bd9Sstevel@tonic-gate 62*9525b14bSRao Shoaib int __evOptMonoTime; 63*9525b14bSRao Shoaib 647c478bd9Sstevel@tonic-gate /* Public. */ 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate int 677c478bd9Sstevel@tonic-gate evCreate(evContext *opaqueCtx) { 687c478bd9Sstevel@tonic-gate evContext_p *ctx; 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate /* Make sure the memory heap is initialized. */ 717c478bd9Sstevel@tonic-gate if (meminit(0, 0) < 0 && errno != EEXIST) 727c478bd9Sstevel@tonic-gate return (-1); 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate OKNEW(ctx); 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate /* Global. */ 777c478bd9Sstevel@tonic-gate ctx->cur = NULL; 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate /* Debugging. */ 807c478bd9Sstevel@tonic-gate ctx->debug = 0; 817c478bd9Sstevel@tonic-gate ctx->output = NULL; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* Connections. */ 847c478bd9Sstevel@tonic-gate ctx->conns = NULL; 857c478bd9Sstevel@tonic-gate INIT_LIST(ctx->accepts); 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /* Files. */ 887c478bd9Sstevel@tonic-gate ctx->files = NULL; 89*9525b14bSRao Shoaib #ifdef USE_POLL 90*9525b14bSRao Shoaib ctx->pollfds = NULL; 917c478bd9Sstevel@tonic-gate ctx->maxnfds = 0; 927c478bd9Sstevel@tonic-gate ctx->firstfd = 0; 937c478bd9Sstevel@tonic-gate emulMaskInit(ctx, rdLast, EV_READ, 1); 947c478bd9Sstevel@tonic-gate emulMaskInit(ctx, rdNext, EV_READ, 0); 957c478bd9Sstevel@tonic-gate emulMaskInit(ctx, wrLast, EV_WRITE, 1); 967c478bd9Sstevel@tonic-gate emulMaskInit(ctx, wrNext, EV_WRITE, 0); 977c478bd9Sstevel@tonic-gate emulMaskInit(ctx, exLast, EV_EXCEPT, 1); 987c478bd9Sstevel@tonic-gate emulMaskInit(ctx, exNext, EV_EXCEPT, 0); 997c478bd9Sstevel@tonic-gate emulMaskInit(ctx, nonblockBefore, EV_WASNONBLOCKING, 0); 100*9525b14bSRao Shoaib #endif /* USE_POLL */ 1017c478bd9Sstevel@tonic-gate FD_ZERO(&ctx->rdNext); 1027c478bd9Sstevel@tonic-gate FD_ZERO(&ctx->wrNext); 1037c478bd9Sstevel@tonic-gate FD_ZERO(&ctx->exNext); 1047c478bd9Sstevel@tonic-gate FD_ZERO(&ctx->nonblockBefore); 1057c478bd9Sstevel@tonic-gate ctx->fdMax = -1; 1067c478bd9Sstevel@tonic-gate ctx->fdNext = NULL; 107*9525b14bSRao Shoaib ctx->fdCount = 0; /*%< Invalidate {rd,wr,ex}Last. */ 108*9525b14bSRao Shoaib #ifndef USE_POLL 1097c478bd9Sstevel@tonic-gate ctx->highestFD = FD_SETSIZE - 1; 110*9525b14bSRao Shoaib memset(ctx->fdTable, 0, sizeof ctx->fdTable); 111*9525b14bSRao Shoaib #else 112*9525b14bSRao Shoaib ctx->highestFD = INT_MAX / sizeof(struct pollfd); 113*9525b14bSRao Shoaib ctx->fdTable = NULL; 114*9525b14bSRao Shoaib #endif /* USE_POLL */ 1157c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 1167c478bd9Sstevel@tonic-gate ctx->lastFdCount = 0; 1177c478bd9Sstevel@tonic-gate #endif 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate /* Streams. */ 1207c478bd9Sstevel@tonic-gate ctx->streams = NULL; 1217c478bd9Sstevel@tonic-gate ctx->strDone = NULL; 1227c478bd9Sstevel@tonic-gate ctx->strLast = NULL; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate /* Timers. */ 1257c478bd9Sstevel@tonic-gate ctx->lastEventTime = evNowTime(); 1267c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 1277c478bd9Sstevel@tonic-gate ctx->lastSelectTime = ctx->lastEventTime; 1287c478bd9Sstevel@tonic-gate #endif 1297c478bd9Sstevel@tonic-gate ctx->timers = evCreateTimers(ctx); 1307c478bd9Sstevel@tonic-gate if (ctx->timers == NULL) 1317c478bd9Sstevel@tonic-gate return (-1); 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate /* Waits. */ 1347c478bd9Sstevel@tonic-gate ctx->waitLists = NULL; 1357c478bd9Sstevel@tonic-gate ctx->waitDone.first = ctx->waitDone.last = NULL; 1367c478bd9Sstevel@tonic-gate ctx->waitDone.prev = ctx->waitDone.next = NULL; 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate opaqueCtx->opaque = ctx; 1397c478bd9Sstevel@tonic-gate return (0); 1407c478bd9Sstevel@tonic-gate } 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate void 1437c478bd9Sstevel@tonic-gate evSetDebug(evContext opaqueCtx, int level, FILE *output) { 1447c478bd9Sstevel@tonic-gate evContext_p *ctx = opaqueCtx.opaque; 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate ctx->debug = level; 1477c478bd9Sstevel@tonic-gate ctx->output = output; 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate int 1517c478bd9Sstevel@tonic-gate evDestroy(evContext opaqueCtx) { 1527c478bd9Sstevel@tonic-gate evContext_p *ctx = opaqueCtx.opaque; 153*9525b14bSRao Shoaib int revs = 424242; /*%< Doug Adams. */ 1547c478bd9Sstevel@tonic-gate evWaitList *this_wl, *next_wl; 1557c478bd9Sstevel@tonic-gate evWait *this_wait, *next_wait; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate /* Connections. */ 1587c478bd9Sstevel@tonic-gate while (revs-- > 0 && ctx->conns != NULL) { 1597c478bd9Sstevel@tonic-gate evConnID id; 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate id.opaque = ctx->conns; 1627c478bd9Sstevel@tonic-gate (void) evCancelConn(opaqueCtx, id); 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate INSIST(revs >= 0); 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate /* Streams. */ 1677c478bd9Sstevel@tonic-gate while (revs-- > 0 && ctx->streams != NULL) { 1687c478bd9Sstevel@tonic-gate evStreamID id; 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate id.opaque = ctx->streams; 1717c478bd9Sstevel@tonic-gate (void) evCancelRW(opaqueCtx, id); 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate /* Files. */ 1757c478bd9Sstevel@tonic-gate while (revs-- > 0 && ctx->files != NULL) { 1767c478bd9Sstevel@tonic-gate evFileID id; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate id.opaque = ctx->files; 1797c478bd9Sstevel@tonic-gate (void) evDeselectFD(opaqueCtx, id); 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate INSIST(revs >= 0); 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate /* Timers. */ 1847c478bd9Sstevel@tonic-gate evDestroyTimers(ctx); 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate /* Waits. */ 1877c478bd9Sstevel@tonic-gate for (this_wl = ctx->waitLists; 1887c478bd9Sstevel@tonic-gate revs-- > 0 && this_wl != NULL; 1897c478bd9Sstevel@tonic-gate this_wl = next_wl) { 1907c478bd9Sstevel@tonic-gate next_wl = this_wl->next; 1917c478bd9Sstevel@tonic-gate for (this_wait = this_wl->first; 1927c478bd9Sstevel@tonic-gate revs-- > 0 && this_wait != NULL; 1937c478bd9Sstevel@tonic-gate this_wait = next_wait) { 1947c478bd9Sstevel@tonic-gate next_wait = this_wait->next; 1957c478bd9Sstevel@tonic-gate FREE(this_wait); 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate FREE(this_wl); 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate for (this_wait = ctx->waitDone.first; 2007c478bd9Sstevel@tonic-gate revs-- > 0 && this_wait != NULL; 2017c478bd9Sstevel@tonic-gate this_wait = next_wait) { 2027c478bd9Sstevel@tonic-gate next_wait = this_wait->next; 2037c478bd9Sstevel@tonic-gate FREE(this_wait); 2047c478bd9Sstevel@tonic-gate } 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate FREE(ctx); 2077c478bd9Sstevel@tonic-gate return (0); 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate int 2117c478bd9Sstevel@tonic-gate evGetNext(evContext opaqueCtx, evEvent *opaqueEv, int options) { 2127c478bd9Sstevel@tonic-gate evContext_p *ctx = opaqueCtx.opaque; 2137c478bd9Sstevel@tonic-gate struct timespec nextTime; 2147c478bd9Sstevel@tonic-gate evTimer *nextTimer; 2157c478bd9Sstevel@tonic-gate evEvent_p *new; 2167c478bd9Sstevel@tonic-gate int x, pselect_errno, timerPast; 2177c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 2187c478bd9Sstevel@tonic-gate struct timespec interval; 2197c478bd9Sstevel@tonic-gate #endif 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate /* Ensure that exactly one of EV_POLL or EV_WAIT was specified. */ 2227c478bd9Sstevel@tonic-gate x = ((options & EV_POLL) != 0) + ((options & EV_WAIT) != 0); 2237c478bd9Sstevel@tonic-gate if (x != 1) 2247c478bd9Sstevel@tonic-gate EV_ERR(EINVAL); 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate /* Get the time of day. We'll do this again after select() blocks. */ 2277c478bd9Sstevel@tonic-gate ctx->lastEventTime = evNowTime(); 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate again: 2307c478bd9Sstevel@tonic-gate /* Finished accept()'s do not require a select(). */ 2317c478bd9Sstevel@tonic-gate if (!EMPTY(ctx->accepts)) { 2327c478bd9Sstevel@tonic-gate OKNEW(new); 2337c478bd9Sstevel@tonic-gate new->type = Accept; 2347c478bd9Sstevel@tonic-gate new->u.accept.this = HEAD(ctx->accepts); 2357c478bd9Sstevel@tonic-gate UNLINK(ctx->accepts, HEAD(ctx->accepts), link); 2367c478bd9Sstevel@tonic-gate opaqueEv->opaque = new; 2377c478bd9Sstevel@tonic-gate return (0); 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate /* Stream IO does not require a select(). */ 2417c478bd9Sstevel@tonic-gate if (ctx->strDone != NULL) { 2427c478bd9Sstevel@tonic-gate OKNEW(new); 2437c478bd9Sstevel@tonic-gate new->type = Stream; 2447c478bd9Sstevel@tonic-gate new->u.stream.this = ctx->strDone; 2457c478bd9Sstevel@tonic-gate ctx->strDone = ctx->strDone->nextDone; 2467c478bd9Sstevel@tonic-gate if (ctx->strDone == NULL) 2477c478bd9Sstevel@tonic-gate ctx->strLast = NULL; 2487c478bd9Sstevel@tonic-gate opaqueEv->opaque = new; 2497c478bd9Sstevel@tonic-gate return (0); 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate /* Waits do not require a select(). */ 2537c478bd9Sstevel@tonic-gate if (ctx->waitDone.first != NULL) { 2547c478bd9Sstevel@tonic-gate OKNEW(new); 2557c478bd9Sstevel@tonic-gate new->type = Wait; 2567c478bd9Sstevel@tonic-gate new->u.wait.this = ctx->waitDone.first; 2577c478bd9Sstevel@tonic-gate ctx->waitDone.first = ctx->waitDone.first->next; 2587c478bd9Sstevel@tonic-gate if (ctx->waitDone.first == NULL) 2597c478bd9Sstevel@tonic-gate ctx->waitDone.last = NULL; 2607c478bd9Sstevel@tonic-gate opaqueEv->opaque = new; 2617c478bd9Sstevel@tonic-gate return (0); 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate /* Get the status and content of the next timer. */ 2657c478bd9Sstevel@tonic-gate if ((nextTimer = heap_element(ctx->timers, 1)) != NULL) { 2667c478bd9Sstevel@tonic-gate nextTime = nextTimer->due; 2677c478bd9Sstevel@tonic-gate timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0); 2687c478bd9Sstevel@tonic-gate } else 269*9525b14bSRao Shoaib timerPast = 0; /*%< Make gcc happy. */ 2707c478bd9Sstevel@tonic-gate evPrintf(ctx, 9, "evGetNext: fdCount %d\n", ctx->fdCount); 2717c478bd9Sstevel@tonic-gate if (ctx->fdCount == 0) { 2727c478bd9Sstevel@tonic-gate static const struct timespec NoTime = {0, 0L}; 2737c478bd9Sstevel@tonic-gate enum { JustPoll, Block, Timer } m; 2747c478bd9Sstevel@tonic-gate struct timespec t, *tp; 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate /* Are there any events at all? */ 2777c478bd9Sstevel@tonic-gate if ((options & EV_WAIT) != 0 && !nextTimer && ctx->fdMax == -1) 2787c478bd9Sstevel@tonic-gate EV_ERR(ENOENT); 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate /* Figure out what select()'s timeout parameter should be. */ 2817c478bd9Sstevel@tonic-gate if ((options & EV_POLL) != 0) { 2827c478bd9Sstevel@tonic-gate m = JustPoll; 2837c478bd9Sstevel@tonic-gate t = NoTime; 2847c478bd9Sstevel@tonic-gate tp = &t; 2857c478bd9Sstevel@tonic-gate } else if (nextTimer == NULL) { 2867c478bd9Sstevel@tonic-gate m = Block; 2877c478bd9Sstevel@tonic-gate /* ``t'' unused. */ 2887c478bd9Sstevel@tonic-gate tp = NULL; 2897c478bd9Sstevel@tonic-gate } else if (timerPast) { 2907c478bd9Sstevel@tonic-gate m = JustPoll; 2917c478bd9Sstevel@tonic-gate t = NoTime; 2927c478bd9Sstevel@tonic-gate tp = &t; 2937c478bd9Sstevel@tonic-gate } else { 2947c478bd9Sstevel@tonic-gate m = Timer; 2957c478bd9Sstevel@tonic-gate /* ``t'' filled in later. */ 2967c478bd9Sstevel@tonic-gate tp = &t; 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 2997c478bd9Sstevel@tonic-gate if (ctx->debug > 0) { 3007c478bd9Sstevel@tonic-gate interval = evSubTime(ctx->lastEventTime, 3017c478bd9Sstevel@tonic-gate ctx->lastSelectTime); 302*9525b14bSRao Shoaib if (interval.tv_sec > 0 || interval.tv_nsec > 0) 3037c478bd9Sstevel@tonic-gate evPrintf(ctx, 1, 3047c478bd9Sstevel@tonic-gate "time between pselect() %u.%09u count %d\n", 3057c478bd9Sstevel@tonic-gate interval.tv_sec, interval.tv_nsec, 3067c478bd9Sstevel@tonic-gate ctx->lastFdCount); 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate #endif 3097c478bd9Sstevel@tonic-gate do { 310*9525b14bSRao Shoaib #ifndef USE_POLL 311*9525b14bSRao Shoaib /* XXX need to copy only the bits we are using. */ 312*9525b14bSRao Shoaib ctx->rdLast = ctx->rdNext; 313*9525b14bSRao Shoaib ctx->wrLast = ctx->wrNext; 314*9525b14bSRao Shoaib ctx->exLast = ctx->exNext; 315*9525b14bSRao Shoaib #else 3167c478bd9Sstevel@tonic-gate /* 3177c478bd9Sstevel@tonic-gate * The pollfd structure uses separate fields for 3187c478bd9Sstevel@tonic-gate * the input and output events (corresponding to 3197c478bd9Sstevel@tonic-gate * the ??Next and ??Last fd sets), so there's no 3207c478bd9Sstevel@tonic-gate * need to copy one to the other. 3217c478bd9Sstevel@tonic-gate */ 322*9525b14bSRao Shoaib #endif /* USE_POLL */ 3237c478bd9Sstevel@tonic-gate if (m == Timer) { 3247c478bd9Sstevel@tonic-gate INSIST(tp == &t); 3257c478bd9Sstevel@tonic-gate t = evSubTime(nextTime, ctx->lastEventTime); 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate /* XXX should predict system's earliness and adjust. */ 3297c478bd9Sstevel@tonic-gate x = pselect(ctx->fdMax+1, 3307c478bd9Sstevel@tonic-gate &ctx->rdLast, &ctx->wrLast, &ctx->exLast, 3317c478bd9Sstevel@tonic-gate tp, NULL); 3327c478bd9Sstevel@tonic-gate pselect_errno = errno; 3337c478bd9Sstevel@tonic-gate 334*9525b14bSRao Shoaib #ifndef USE_POLL 3357c478bd9Sstevel@tonic-gate evPrintf(ctx, 4, "select() returns %d (err: %s)\n", 3367c478bd9Sstevel@tonic-gate x, (x == -1) ? strerror(errno) : "none"); 337*9525b14bSRao Shoaib #else 338*9525b14bSRao Shoaib evPrintf(ctx, 4, "poll() returns %d (err: %s)\n", 339*9525b14bSRao Shoaib x, (x == -1) ? strerror(errno) : "none"); 340*9525b14bSRao Shoaib #endif /* USE_POLL */ 3417c478bd9Sstevel@tonic-gate /* Anything but a poll can change the time. */ 3427c478bd9Sstevel@tonic-gate if (m != JustPoll) 3437c478bd9Sstevel@tonic-gate ctx->lastEventTime = evNowTime(); 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate /* Select() likes to finish about 10ms early. */ 3467c478bd9Sstevel@tonic-gate } while (x == 0 && m == Timer && 3477c478bd9Sstevel@tonic-gate evCmpTime(ctx->lastEventTime, nextTime) < 0); 3487c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 3497c478bd9Sstevel@tonic-gate ctx->lastSelectTime = ctx->lastEventTime; 3507c478bd9Sstevel@tonic-gate #endif 3517c478bd9Sstevel@tonic-gate if (x < 0) { 3527c478bd9Sstevel@tonic-gate if (pselect_errno == EINTR) { 3537c478bd9Sstevel@tonic-gate if ((options & EV_NULL) != 0) 3547c478bd9Sstevel@tonic-gate goto again; 3557c478bd9Sstevel@tonic-gate OKNEW(new); 3567c478bd9Sstevel@tonic-gate new->type = Null; 3577c478bd9Sstevel@tonic-gate /* No data. */ 3587c478bd9Sstevel@tonic-gate opaqueEv->opaque = new; 3597c478bd9Sstevel@tonic-gate return (0); 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate if (pselect_errno == EBADF) { 3627c478bd9Sstevel@tonic-gate for (x = 0; x <= ctx->fdMax; x++) { 3637c478bd9Sstevel@tonic-gate struct stat sb; 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate if (FD_ISSET(x, &ctx->rdNext) == 0 && 3667c478bd9Sstevel@tonic-gate FD_ISSET(x, &ctx->wrNext) == 0 && 3677c478bd9Sstevel@tonic-gate FD_ISSET(x, &ctx->exNext) == 0) 3687c478bd9Sstevel@tonic-gate continue; 3697c478bd9Sstevel@tonic-gate if (fstat(x, &sb) == -1 && 3707c478bd9Sstevel@tonic-gate errno == EBADF) 3717c478bd9Sstevel@tonic-gate evPrintf(ctx, 1, "EBADF: %d\n", 3727c478bd9Sstevel@tonic-gate x); 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate abort(); 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate EV_ERR(pselect_errno); 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate if (x == 0 && (nextTimer == NULL || !timerPast) && 3797c478bd9Sstevel@tonic-gate (options & EV_POLL)) 3807c478bd9Sstevel@tonic-gate EV_ERR(EWOULDBLOCK); 3817c478bd9Sstevel@tonic-gate ctx->fdCount = x; 3827c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 3837c478bd9Sstevel@tonic-gate ctx->lastFdCount = x; 3847c478bd9Sstevel@tonic-gate #endif 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate INSIST(nextTimer || ctx->fdCount); 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate /* Timers go first since we'd like them to be accurate. */ 3897c478bd9Sstevel@tonic-gate if (nextTimer && !timerPast) { 3907c478bd9Sstevel@tonic-gate /* Has anything happened since we blocked? */ 3917c478bd9Sstevel@tonic-gate timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0); 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate if (nextTimer && timerPast) { 3947c478bd9Sstevel@tonic-gate OKNEW(new); 3957c478bd9Sstevel@tonic-gate new->type = Timer; 3967c478bd9Sstevel@tonic-gate new->u.timer.this = nextTimer; 3977c478bd9Sstevel@tonic-gate opaqueEv->opaque = new; 3987c478bd9Sstevel@tonic-gate return (0); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate /* No timers, so there should be a ready file descriptor. */ 4027c478bd9Sstevel@tonic-gate x = 0; 4037c478bd9Sstevel@tonic-gate while (ctx->fdCount > 0) { 4047c478bd9Sstevel@tonic-gate evFile *fid; 4057c478bd9Sstevel@tonic-gate int fd, eventmask; 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate if (ctx->fdNext == NULL) { 4087c478bd9Sstevel@tonic-gate if (++x == 2) { 4097c478bd9Sstevel@tonic-gate /* 4107c478bd9Sstevel@tonic-gate * Hitting the end twice means that the last 4117c478bd9Sstevel@tonic-gate * select() found some FD's which have since 4127c478bd9Sstevel@tonic-gate * been deselected. 4137c478bd9Sstevel@tonic-gate * 4147c478bd9Sstevel@tonic-gate * On some systems, the count returned by 4157c478bd9Sstevel@tonic-gate * selects is the total number of bits in 4167c478bd9Sstevel@tonic-gate * all masks that are set, and on others it's 4177c478bd9Sstevel@tonic-gate * the number of fd's that have some bit set, 4187c478bd9Sstevel@tonic-gate * and on others, it's just broken. We 4197c478bd9Sstevel@tonic-gate * always assume that it's the number of 4207c478bd9Sstevel@tonic-gate * bits set in all masks, because that's what 4217c478bd9Sstevel@tonic-gate * the man page says it should do, and 4227c478bd9Sstevel@tonic-gate * the worst that can happen is we do an 4237c478bd9Sstevel@tonic-gate * extra select(). 4247c478bd9Sstevel@tonic-gate */ 4257c478bd9Sstevel@tonic-gate ctx->fdCount = 0; 4267c478bd9Sstevel@tonic-gate break; 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate ctx->fdNext = ctx->files; 4297c478bd9Sstevel@tonic-gate } 4307c478bd9Sstevel@tonic-gate fid = ctx->fdNext; 4317c478bd9Sstevel@tonic-gate ctx->fdNext = fid->next; 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate fd = fid->fd; 4347c478bd9Sstevel@tonic-gate eventmask = 0; 4357c478bd9Sstevel@tonic-gate if (FD_ISSET(fd, &ctx->rdLast)) 4367c478bd9Sstevel@tonic-gate eventmask |= EV_READ; 4377c478bd9Sstevel@tonic-gate if (FD_ISSET(fd, &ctx->wrLast)) 4387c478bd9Sstevel@tonic-gate eventmask |= EV_WRITE; 4397c478bd9Sstevel@tonic-gate if (FD_ISSET(fd, &ctx->exLast)) 4407c478bd9Sstevel@tonic-gate eventmask |= EV_EXCEPT; 4417c478bd9Sstevel@tonic-gate eventmask &= fid->eventmask; 4427c478bd9Sstevel@tonic-gate if (eventmask != 0) { 4437c478bd9Sstevel@tonic-gate if ((eventmask & EV_READ) != 0) { 4447c478bd9Sstevel@tonic-gate FD_CLR(fd, &ctx->rdLast); 4457c478bd9Sstevel@tonic-gate ctx->fdCount--; 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate if ((eventmask & EV_WRITE) != 0) { 4487c478bd9Sstevel@tonic-gate FD_CLR(fd, &ctx->wrLast); 4497c478bd9Sstevel@tonic-gate ctx->fdCount--; 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate if ((eventmask & EV_EXCEPT) != 0) { 4527c478bd9Sstevel@tonic-gate FD_CLR(fd, &ctx->exLast); 4537c478bd9Sstevel@tonic-gate ctx->fdCount--; 4547c478bd9Sstevel@tonic-gate } 4557c478bd9Sstevel@tonic-gate OKNEW(new); 4567c478bd9Sstevel@tonic-gate new->type = File; 4577c478bd9Sstevel@tonic-gate new->u.file.this = fid; 4587c478bd9Sstevel@tonic-gate new->u.file.eventmask = eventmask; 4597c478bd9Sstevel@tonic-gate opaqueEv->opaque = new; 4607c478bd9Sstevel@tonic-gate return (0); 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate if (ctx->fdCount < 0) { 4647c478bd9Sstevel@tonic-gate /* 4657c478bd9Sstevel@tonic-gate * select()'s count is off on a number of systems, and 4667c478bd9Sstevel@tonic-gate * can result in fdCount < 0. 4677c478bd9Sstevel@tonic-gate */ 4687c478bd9Sstevel@tonic-gate evPrintf(ctx, 4, "fdCount < 0 (%d)\n", ctx->fdCount); 4697c478bd9Sstevel@tonic-gate ctx->fdCount = 0; 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate /* We get here if the caller deselect()'s an FD. Gag me with a goto. */ 4737c478bd9Sstevel@tonic-gate goto again; 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate int 4777c478bd9Sstevel@tonic-gate evDispatch(evContext opaqueCtx, evEvent opaqueEv) { 4787c478bd9Sstevel@tonic-gate evContext_p *ctx = opaqueCtx.opaque; 4797c478bd9Sstevel@tonic-gate evEvent_p *ev = opaqueEv.opaque; 4807c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 4817c478bd9Sstevel@tonic-gate void *func; 4827c478bd9Sstevel@tonic-gate struct timespec start_time; 4837c478bd9Sstevel@tonic-gate struct timespec interval; 4847c478bd9Sstevel@tonic-gate #endif 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 4877c478bd9Sstevel@tonic-gate if (ctx->debug > 0) 4887c478bd9Sstevel@tonic-gate start_time = evNowTime(); 4897c478bd9Sstevel@tonic-gate #endif 4907c478bd9Sstevel@tonic-gate ctx->cur = ev; 4917c478bd9Sstevel@tonic-gate switch (ev->type) { 4927c478bd9Sstevel@tonic-gate case Accept: { 4937c478bd9Sstevel@tonic-gate evAccept *this = ev->u.accept.this; 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate evPrintf(ctx, 5, 4967c478bd9Sstevel@tonic-gate "Dispatch.Accept: fd %d -> %d, func %p, uap %p\n", 4977c478bd9Sstevel@tonic-gate this->conn->fd, this->fd, 4987c478bd9Sstevel@tonic-gate this->conn->func, this->conn->uap); 4997c478bd9Sstevel@tonic-gate errno = this->ioErrno; 5007c478bd9Sstevel@tonic-gate (this->conn->func)(opaqueCtx, this->conn->uap, this->fd, 5017c478bd9Sstevel@tonic-gate &this->la, this->lalen, 5027c478bd9Sstevel@tonic-gate &this->ra, this->ralen); 5037c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 5047c478bd9Sstevel@tonic-gate func = this->conn->func; 5057c478bd9Sstevel@tonic-gate #endif 5067c478bd9Sstevel@tonic-gate break; 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate case File: { 5097c478bd9Sstevel@tonic-gate evFile *this = ev->u.file.this; 5107c478bd9Sstevel@tonic-gate int eventmask = ev->u.file.eventmask; 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate evPrintf(ctx, 5, 5137c478bd9Sstevel@tonic-gate "Dispatch.File: fd %d, mask 0x%x, func %p, uap %p\n", 5147c478bd9Sstevel@tonic-gate this->fd, this->eventmask, this->func, this->uap); 5157c478bd9Sstevel@tonic-gate (this->func)(opaqueCtx, this->uap, this->fd, eventmask); 5167c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 5177c478bd9Sstevel@tonic-gate func = this->func; 5187c478bd9Sstevel@tonic-gate #endif 5197c478bd9Sstevel@tonic-gate break; 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate case Stream: { 5227c478bd9Sstevel@tonic-gate evStream *this = ev->u.stream.this; 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate evPrintf(ctx, 5, 5257c478bd9Sstevel@tonic-gate "Dispatch.Stream: fd %d, func %p, uap %p\n", 5267c478bd9Sstevel@tonic-gate this->fd, this->func, this->uap); 5277c478bd9Sstevel@tonic-gate errno = this->ioErrno; 5287c478bd9Sstevel@tonic-gate (this->func)(opaqueCtx, this->uap, this->fd, this->ioDone); 5297c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 5307c478bd9Sstevel@tonic-gate func = this->func; 5317c478bd9Sstevel@tonic-gate #endif 5327c478bd9Sstevel@tonic-gate break; 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate case Timer: { 5357c478bd9Sstevel@tonic-gate evTimer *this = ev->u.timer.this; 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate evPrintf(ctx, 5, "Dispatch.Timer: func %p, uap %p\n", 5387c478bd9Sstevel@tonic-gate this->func, this->uap); 5397c478bd9Sstevel@tonic-gate (this->func)(opaqueCtx, this->uap, this->due, this->inter); 5407c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 5417c478bd9Sstevel@tonic-gate func = this->func; 5427c478bd9Sstevel@tonic-gate #endif 5437c478bd9Sstevel@tonic-gate break; 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate case Wait: { 5467c478bd9Sstevel@tonic-gate evWait *this = ev->u.wait.this; 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate evPrintf(ctx, 5, 5497c478bd9Sstevel@tonic-gate "Dispatch.Wait: tag %p, func %p, uap %p\n", 5507c478bd9Sstevel@tonic-gate this->tag, this->func, this->uap); 5517c478bd9Sstevel@tonic-gate (this->func)(opaqueCtx, this->uap, this->tag); 5527c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 5537c478bd9Sstevel@tonic-gate func = this->func; 5547c478bd9Sstevel@tonic-gate #endif 5557c478bd9Sstevel@tonic-gate break; 5567c478bd9Sstevel@tonic-gate } 5577c478bd9Sstevel@tonic-gate case Null: { 5587c478bd9Sstevel@tonic-gate /* No work. */ 5597c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 5607c478bd9Sstevel@tonic-gate func = NULL; 5617c478bd9Sstevel@tonic-gate #endif 5627c478bd9Sstevel@tonic-gate break; 5637c478bd9Sstevel@tonic-gate } 5647c478bd9Sstevel@tonic-gate default: { 5657c478bd9Sstevel@tonic-gate abort(); 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 5697c478bd9Sstevel@tonic-gate if (ctx->debug > 0) { 5707c478bd9Sstevel@tonic-gate interval = evSubTime(evNowTime(), start_time); 5717c478bd9Sstevel@tonic-gate /* 5727c478bd9Sstevel@tonic-gate * Complain if it took longer than 50 milliseconds. 5737c478bd9Sstevel@tonic-gate * 5747c478bd9Sstevel@tonic-gate * We call getuid() to make an easy to find mark in a kernel 5757c478bd9Sstevel@tonic-gate * trace. 5767c478bd9Sstevel@tonic-gate */ 5777c478bd9Sstevel@tonic-gate if (interval.tv_sec > 0 || interval.tv_nsec > 50000000) 5787c478bd9Sstevel@tonic-gate evPrintf(ctx, 1, 5797c478bd9Sstevel@tonic-gate "dispatch interval %u.%09u uid %d type %d func %p\n", 5807c478bd9Sstevel@tonic-gate interval.tv_sec, interval.tv_nsec, 5817c478bd9Sstevel@tonic-gate getuid(), ev->type, func); 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate #endif 5847c478bd9Sstevel@tonic-gate ctx->cur = NULL; 5857c478bd9Sstevel@tonic-gate evDrop(opaqueCtx, opaqueEv); 5867c478bd9Sstevel@tonic-gate return (0); 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate void 5907c478bd9Sstevel@tonic-gate evDrop(evContext opaqueCtx, evEvent opaqueEv) { 5917c478bd9Sstevel@tonic-gate evContext_p *ctx = opaqueCtx.opaque; 5927c478bd9Sstevel@tonic-gate evEvent_p *ev = opaqueEv.opaque; 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate switch (ev->type) { 5957c478bd9Sstevel@tonic-gate case Accept: { 5967c478bd9Sstevel@tonic-gate FREE(ev->u.accept.this); 5977c478bd9Sstevel@tonic-gate break; 5987c478bd9Sstevel@tonic-gate } 5997c478bd9Sstevel@tonic-gate case File: { 6007c478bd9Sstevel@tonic-gate /* No work. */ 6017c478bd9Sstevel@tonic-gate break; 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate case Stream: { 6047c478bd9Sstevel@tonic-gate evStreamID id; 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate id.opaque = ev->u.stream.this; 6077c478bd9Sstevel@tonic-gate (void) evCancelRW(opaqueCtx, id); 6087c478bd9Sstevel@tonic-gate break; 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate case Timer: { 6117c478bd9Sstevel@tonic-gate evTimer *this = ev->u.timer.this; 6127c478bd9Sstevel@tonic-gate evTimerID opaque; 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate /* Check to see whether the user func cleared the timer. */ 6157c478bd9Sstevel@tonic-gate if (heap_element(ctx->timers, this->index) != this) { 6167c478bd9Sstevel@tonic-gate evPrintf(ctx, 5, "Dispatch.Timer: timer rm'd?\n"); 6177c478bd9Sstevel@tonic-gate break; 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate /* 6207c478bd9Sstevel@tonic-gate * Timer is still there. Delete it if it has expired, 6217c478bd9Sstevel@tonic-gate * otherwise set it according to its next interval. 6227c478bd9Sstevel@tonic-gate */ 623*9525b14bSRao Shoaib if (this->inter.tv_sec == (time_t)0 && 624*9525b14bSRao Shoaib this->inter.tv_nsec == 0L) { 6257c478bd9Sstevel@tonic-gate opaque.opaque = this; 6267c478bd9Sstevel@tonic-gate (void) evClearTimer(opaqueCtx, opaque); 6277c478bd9Sstevel@tonic-gate } else { 6287c478bd9Sstevel@tonic-gate opaque.opaque = this; 6297c478bd9Sstevel@tonic-gate (void) evResetTimer(opaqueCtx, opaque, this->func, 6307c478bd9Sstevel@tonic-gate this->uap, 631*9525b14bSRao Shoaib evAddTime((this->mode & EV_TMR_RATE) ? 632*9525b14bSRao Shoaib this->due : 633*9525b14bSRao Shoaib ctx->lastEventTime, 6347c478bd9Sstevel@tonic-gate this->inter), 6357c478bd9Sstevel@tonic-gate this->inter); 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate break; 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate case Wait: { 6407c478bd9Sstevel@tonic-gate FREE(ev->u.wait.this); 6417c478bd9Sstevel@tonic-gate break; 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate case Null: { 6447c478bd9Sstevel@tonic-gate /* No work. */ 6457c478bd9Sstevel@tonic-gate break; 6467c478bd9Sstevel@tonic-gate } 6477c478bd9Sstevel@tonic-gate default: { 6487c478bd9Sstevel@tonic-gate abort(); 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate } 6517c478bd9Sstevel@tonic-gate FREE(ev); 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate int 6557c478bd9Sstevel@tonic-gate evMainLoop(evContext opaqueCtx) { 6567c478bd9Sstevel@tonic-gate evEvent event; 6577c478bd9Sstevel@tonic-gate int x; 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0) 6607c478bd9Sstevel@tonic-gate if ((x = evDispatch(opaqueCtx, event)) < 0) 6617c478bd9Sstevel@tonic-gate break; 6627c478bd9Sstevel@tonic-gate return (x); 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate int 6667c478bd9Sstevel@tonic-gate evHighestFD(evContext opaqueCtx) { 6677c478bd9Sstevel@tonic-gate evContext_p *ctx = opaqueCtx.opaque; 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate return (ctx->highestFD); 6707c478bd9Sstevel@tonic-gate } 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate void 6737c478bd9Sstevel@tonic-gate evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) { 6747c478bd9Sstevel@tonic-gate va_list ap; 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate va_start(ap, fmt); 6777c478bd9Sstevel@tonic-gate if (ctx->output != NULL && ctx->debug >= level) { 6787c478bd9Sstevel@tonic-gate vfprintf(ctx->output, fmt, ap); 6797c478bd9Sstevel@tonic-gate fflush(ctx->output); 6807c478bd9Sstevel@tonic-gate } 6817c478bd9Sstevel@tonic-gate va_end(ap); 6827c478bd9Sstevel@tonic-gate } 6837c478bd9Sstevel@tonic-gate 684*9525b14bSRao Shoaib int 685*9525b14bSRao Shoaib evSetOption(evContext *opaqueCtx, const char *option, int value) { 686*9525b14bSRao Shoaib /* evContext_p *ctx = opaqueCtx->opaque; */ 687*9525b14bSRao Shoaib 688*9525b14bSRao Shoaib UNUSED(opaqueCtx); 689*9525b14bSRao Shoaib UNUSED(value); 690*9525b14bSRao Shoaib #ifndef CLOCK_MONOTONIC 691*9525b14bSRao Shoaib UNUSED(option); 692*9525b14bSRao Shoaib #endif 693*9525b14bSRao Shoaib 694*9525b14bSRao Shoaib #ifdef CLOCK_MONOTONIC 695*9525b14bSRao Shoaib if (strcmp(option, "monotime") == 0) { 696*9525b14bSRao Shoaib if (opaqueCtx != NULL) 697*9525b14bSRao Shoaib errno = EINVAL; 698*9525b14bSRao Shoaib if (value == 0 || value == 1) { 699*9525b14bSRao Shoaib __evOptMonoTime = value; 700*9525b14bSRao Shoaib return (0); 701*9525b14bSRao Shoaib } else { 702*9525b14bSRao Shoaib errno = EINVAL; 703*9525b14bSRao Shoaib return (-1); 704*9525b14bSRao Shoaib } 705*9525b14bSRao Shoaib } 706*9525b14bSRao Shoaib #endif 707*9525b14bSRao Shoaib errno = ENOENT; 708*9525b14bSRao Shoaib return (-1); 709*9525b14bSRao Shoaib } 710*9525b14bSRao Shoaib 711*9525b14bSRao Shoaib int 712*9525b14bSRao Shoaib evGetOption(evContext *opaqueCtx, const char *option, int *value) { 713*9525b14bSRao Shoaib /* evContext_p *ctx = opaqueCtx->opaque; */ 714*9525b14bSRao Shoaib 715*9525b14bSRao Shoaib UNUSED(opaqueCtx); 716*9525b14bSRao Shoaib #ifndef CLOCK_MONOTONIC 717*9525b14bSRao Shoaib UNUSED(value); 718*9525b14bSRao Shoaib UNUSED(option); 719*9525b14bSRao Shoaib #endif 720*9525b14bSRao Shoaib 721*9525b14bSRao Shoaib #ifdef CLOCK_MONOTONIC 722*9525b14bSRao Shoaib if (strcmp(option, "monotime") == 0) { 723*9525b14bSRao Shoaib if (opaqueCtx != NULL) 724*9525b14bSRao Shoaib errno = EINVAL; 725*9525b14bSRao Shoaib *value = __evOptMonoTime; 726*9525b14bSRao Shoaib return (0); 727*9525b14bSRao Shoaib } 728*9525b14bSRao Shoaib #endif 729*9525b14bSRao Shoaib errno = ENOENT; 730*9525b14bSRao Shoaib return (-1); 731*9525b14bSRao Shoaib } 732*9525b14bSRao Shoaib 733*9525b14bSRao Shoaib #if defined(NEED_PSELECT) || defined(USE_POLL) 7347c478bd9Sstevel@tonic-gate /* XXX needs to move to the porting library. */ 7357c478bd9Sstevel@tonic-gate static int 7367c478bd9Sstevel@tonic-gate pselect(int nfds, void *rfds, void *wfds, void *efds, 7377c478bd9Sstevel@tonic-gate struct timespec *tsp, 7387c478bd9Sstevel@tonic-gate const sigset_t *sigmask) 7397c478bd9Sstevel@tonic-gate { 7407c478bd9Sstevel@tonic-gate struct timeval tv, *tvp; 7417c478bd9Sstevel@tonic-gate sigset_t sigs; 7427c478bd9Sstevel@tonic-gate int n; 743*9525b14bSRao Shoaib #ifdef USE_POLL 7447c478bd9Sstevel@tonic-gate int polltimeout = INFTIM; 7457c478bd9Sstevel@tonic-gate evContext_p *ctx; 7467c478bd9Sstevel@tonic-gate struct pollfd *fds; 7477c478bd9Sstevel@tonic-gate nfds_t pnfds; 748*9525b14bSRao Shoaib 749*9525b14bSRao Shoaib UNUSED(nfds); 750*9525b14bSRao Shoaib #endif /* USE_POLL */ 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate if (tsp) { 7537c478bd9Sstevel@tonic-gate tvp = &tv; 7547c478bd9Sstevel@tonic-gate tv = evTimeVal(*tsp); 755*9525b14bSRao Shoaib #ifdef USE_POLL 7567c478bd9Sstevel@tonic-gate polltimeout = 1000 * tv.tv_sec + tv.tv_usec / 1000; 757*9525b14bSRao Shoaib #endif /* USE_POLL */ 7587c478bd9Sstevel@tonic-gate } else 7597c478bd9Sstevel@tonic-gate tvp = NULL; 7607c478bd9Sstevel@tonic-gate if (sigmask) 7617c478bd9Sstevel@tonic-gate sigprocmask(SIG_SETMASK, sigmask, &sigs); 762*9525b14bSRao Shoaib #ifndef USE_POLL 763*9525b14bSRao Shoaib n = select(nfds, rfds, wfds, efds, tvp); 764*9525b14bSRao Shoaib #else 7657c478bd9Sstevel@tonic-gate /* 7667c478bd9Sstevel@tonic-gate * rfds, wfds, and efds should all be from the same evContext_p, 7677c478bd9Sstevel@tonic-gate * so any of them will do. If they're all NULL, the caller is 7687c478bd9Sstevel@tonic-gate * presumably calling us to block. 7697c478bd9Sstevel@tonic-gate */ 770*9525b14bSRao Shoaib if (rfds != NULL) 7717c478bd9Sstevel@tonic-gate ctx = ((__evEmulMask *)rfds)->ctx; 772*9525b14bSRao Shoaib else if (wfds != NULL) 7737c478bd9Sstevel@tonic-gate ctx = ((__evEmulMask *)wfds)->ctx; 774*9525b14bSRao Shoaib else if (efds != NULL) 7757c478bd9Sstevel@tonic-gate ctx = ((__evEmulMask *)efds)->ctx; 7767c478bd9Sstevel@tonic-gate else 777*9525b14bSRao Shoaib ctx = NULL; 778*9525b14bSRao Shoaib if (ctx != NULL && ctx->fdMax != -1) { 7797c478bd9Sstevel@tonic-gate fds = &(ctx->pollfds[ctx->firstfd]); 7807c478bd9Sstevel@tonic-gate pnfds = ctx->fdMax - ctx->firstfd + 1; 7817c478bd9Sstevel@tonic-gate } else { 782*9525b14bSRao Shoaib fds = NULL; 7837c478bd9Sstevel@tonic-gate pnfds = 0; 7847c478bd9Sstevel@tonic-gate } 7857c478bd9Sstevel@tonic-gate n = poll(fds, pnfds, polltimeout); 7867c478bd9Sstevel@tonic-gate if (n > 0) { 7877c478bd9Sstevel@tonic-gate int i, e; 788*9525b14bSRao Shoaib 789*9525b14bSRao Shoaib INSIST(ctx != NULL); 7907c478bd9Sstevel@tonic-gate for (e = 0, i = ctx->firstfd; i <= ctx->fdMax; i++) { 7917c478bd9Sstevel@tonic-gate if (ctx->pollfds[i].fd < 0) 7927c478bd9Sstevel@tonic-gate continue; 7937c478bd9Sstevel@tonic-gate if (FD_ISSET(i, &ctx->rdLast)) 7947c478bd9Sstevel@tonic-gate e++; 7957c478bd9Sstevel@tonic-gate if (FD_ISSET(i, &ctx->wrLast)) 7967c478bd9Sstevel@tonic-gate e++; 7977c478bd9Sstevel@tonic-gate if (FD_ISSET(i, &ctx->exLast)) 7987c478bd9Sstevel@tonic-gate e++; 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate n = e; 8017c478bd9Sstevel@tonic-gate } 802*9525b14bSRao Shoaib #endif /* USE_POLL */ 8037c478bd9Sstevel@tonic-gate if (sigmask) 8047c478bd9Sstevel@tonic-gate sigprocmask(SIG_SETMASK, &sigs, NULL); 8057c478bd9Sstevel@tonic-gate if (tsp) 8067c478bd9Sstevel@tonic-gate *tsp = evTimeSpec(tv); 8077c478bd9Sstevel@tonic-gate return (n); 8087c478bd9Sstevel@tonic-gate } 8097c478bd9Sstevel@tonic-gate #endif 8107c478bd9Sstevel@tonic-gate 811*9525b14bSRao Shoaib #ifdef USE_POLL 812*9525b14bSRao Shoaib int 8137c478bd9Sstevel@tonic-gate evPollfdRealloc(evContext_p *ctx, int pollfd_chunk_size, int fd) { 8147c478bd9Sstevel@tonic-gate 815*9525b14bSRao Shoaib int i, maxnfds; 816*9525b14bSRao Shoaib void *pollfds, *fdTable; 8177c478bd9Sstevel@tonic-gate 818*9525b14bSRao Shoaib if (fd < ctx->maxnfds) 819*9525b14bSRao Shoaib return (0); 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate /* Don't allow ridiculously small values for pollfd_chunk_size */ 8227c478bd9Sstevel@tonic-gate if (pollfd_chunk_size < 20) 8237c478bd9Sstevel@tonic-gate pollfd_chunk_size = 20; 8247c478bd9Sstevel@tonic-gate 825*9525b14bSRao Shoaib maxnfds = (1 + (fd/pollfd_chunk_size)) * pollfd_chunk_size; 8267c478bd9Sstevel@tonic-gate 827*9525b14bSRao Shoaib pollfds = realloc(ctx->pollfds, maxnfds * sizeof(*ctx->pollfds)); 828*9525b14bSRao Shoaib if (pollfds != NULL) 829*9525b14bSRao Shoaib ctx->pollfds = pollfds; 830*9525b14bSRao Shoaib fdTable = realloc(ctx->fdTable, maxnfds * sizeof(*ctx->fdTable)); 831*9525b14bSRao Shoaib if (fdTable != NULL) 832*9525b14bSRao Shoaib ctx->fdTable = fdTable; 8337c478bd9Sstevel@tonic-gate 834*9525b14bSRao Shoaib if (pollfds == NULL || fdTable == NULL) { 835*9525b14bSRao Shoaib evPrintf(ctx, 2, "pollfd() realloc (%ld) failed\n", 836*9525b14bSRao Shoaib (long)maxnfds*sizeof(struct pollfd)); 837*9525b14bSRao Shoaib return (-1); 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate 840*9525b14bSRao Shoaib for (i = ctx->maxnfds; i < maxnfds; i++) { 8417c478bd9Sstevel@tonic-gate ctx->pollfds[i].fd = -1; 8427c478bd9Sstevel@tonic-gate ctx->pollfds[i].events = 0; 8437c478bd9Sstevel@tonic-gate ctx->fdTable[i] = 0; 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate 846*9525b14bSRao Shoaib ctx->maxnfds = maxnfds; 8477c478bd9Sstevel@tonic-gate 848*9525b14bSRao Shoaib return (0); 8497c478bd9Sstevel@tonic-gate } 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate /* Find the appropriate 'events' or 'revents' field in the pollfds array */ 8527c478bd9Sstevel@tonic-gate short * 8537c478bd9Sstevel@tonic-gate __fd_eventfield(int fd, __evEmulMask *maskp) { 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate evContext_p *ctx = (evContext_p *)maskp->ctx; 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate if (!maskp->result || maskp->type == EV_WASNONBLOCKING) 8587c478bd9Sstevel@tonic-gate return (&(ctx->pollfds[fd].events)); 8597c478bd9Sstevel@tonic-gate else 8607c478bd9Sstevel@tonic-gate return (&(ctx->pollfds[fd].revents)); 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate /* Translate to poll(2) event */ 8647c478bd9Sstevel@tonic-gate short 8657c478bd9Sstevel@tonic-gate __poll_event(__evEmulMask *maskp) { 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate switch ((maskp)->type) { 8687c478bd9Sstevel@tonic-gate case EV_READ: 8697c478bd9Sstevel@tonic-gate return (POLLRDNORM); 8707c478bd9Sstevel@tonic-gate case EV_WRITE: 8717c478bd9Sstevel@tonic-gate return (POLLWRNORM); 8727c478bd9Sstevel@tonic-gate case EV_EXCEPT: 8737c478bd9Sstevel@tonic-gate return (POLLRDBAND | POLLPRI | POLLWRBAND); 8747c478bd9Sstevel@tonic-gate case EV_WASNONBLOCKING: 8757c478bd9Sstevel@tonic-gate return (POLLHUP); 8767c478bd9Sstevel@tonic-gate default: 8777c478bd9Sstevel@tonic-gate return (0); 8787c478bd9Sstevel@tonic-gate } 8797c478bd9Sstevel@tonic-gate } 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate /* 8827c478bd9Sstevel@tonic-gate * Clear the events corresponding to the specified mask. If this leaves 8837c478bd9Sstevel@tonic-gate * the events mask empty (apart from the POLLHUP bit), set the fd field 8847c478bd9Sstevel@tonic-gate * to -1 so that poll(2) will ignore this fd. 8857c478bd9Sstevel@tonic-gate */ 8867c478bd9Sstevel@tonic-gate void 8877c478bd9Sstevel@tonic-gate __fd_clr(int fd, __evEmulMask *maskp) { 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate evContext_p *ctx = maskp->ctx; 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate *__fd_eventfield(fd, maskp) &= ~__poll_event(maskp); 8927c478bd9Sstevel@tonic-gate if ((ctx->pollfds[fd].events & ~POLLHUP) == 0) { 8937c478bd9Sstevel@tonic-gate ctx->pollfds[fd].fd = -1; 894*9525b14bSRao Shoaib if (fd == ctx->fdMax) 895*9525b14bSRao Shoaib while (ctx->fdMax > ctx->firstfd && 896*9525b14bSRao Shoaib ctx->pollfds[ctx->fdMax].fd < 0) 897*9525b14bSRao Shoaib ctx->fdMax--; 898*9525b14bSRao Shoaib if (fd == ctx->firstfd) 899*9525b14bSRao Shoaib while (ctx->firstfd <= ctx->fdMax && 900*9525b14bSRao Shoaib ctx->pollfds[ctx->firstfd].fd < 0) 901*9525b14bSRao Shoaib ctx->firstfd++; 902*9525b14bSRao Shoaib /* 903*9525b14bSRao Shoaib * Do we have a empty set of descriptors? 904*9525b14bSRao Shoaib */ 905*9525b14bSRao Shoaib if (ctx->firstfd > ctx->fdMax) { 906*9525b14bSRao Shoaib ctx->fdMax = -1; 907*9525b14bSRao Shoaib ctx->firstfd = 0; 908*9525b14bSRao Shoaib } 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate /* 9137c478bd9Sstevel@tonic-gate * Set the events bit(s) corresponding to the specified mask. If the events 9147c478bd9Sstevel@tonic-gate * field has any other bits than POLLHUP set, also set the fd field so that 9157c478bd9Sstevel@tonic-gate * poll(2) will watch this fd. 9167c478bd9Sstevel@tonic-gate */ 9177c478bd9Sstevel@tonic-gate void 9187c478bd9Sstevel@tonic-gate __fd_set(int fd, __evEmulMask *maskp) { 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate evContext_p *ctx = maskp->ctx; 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate *__fd_eventfield(fd, maskp) |= __poll_event(maskp); 9237c478bd9Sstevel@tonic-gate if ((ctx->pollfds[fd].events & ~POLLHUP) != 0) { 9247c478bd9Sstevel@tonic-gate ctx->pollfds[fd].fd = fd; 925*9525b14bSRao Shoaib if (fd < ctx->firstfd || ctx->fdMax == -1) 9267c478bd9Sstevel@tonic-gate ctx->firstfd = fd; 9277c478bd9Sstevel@tonic-gate if (fd > ctx->fdMax) 9287c478bd9Sstevel@tonic-gate ctx->fdMax = fd; 9297c478bd9Sstevel@tonic-gate } 9307c478bd9Sstevel@tonic-gate } 931*9525b14bSRao Shoaib #endif /* USE_POLL */ 932*9525b14bSRao Shoaib 933*9525b14bSRao Shoaib /*! \file */ 934