10Sstevel@tonic-gate /* 2*11038SRao.Shoaib@Sun.COM * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 30Sstevel@tonic-gate * Copyright (c) 1995-1999 by Internet Software Consortium 40Sstevel@tonic-gate * 50Sstevel@tonic-gate * Permission to use, copy, modify, and distribute this software for any 60Sstevel@tonic-gate * purpose with or without fee is hereby granted, provided that the above 70Sstevel@tonic-gate * copyright notice and this permission notice appear in all copies. 80Sstevel@tonic-gate * 9*11038SRao.Shoaib@Sun.COM * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10*11038SRao.Shoaib@Sun.COM * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11*11038SRao.Shoaib@Sun.COM * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12*11038SRao.Shoaib@Sun.COM * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13*11038SRao.Shoaib@Sun.COM * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14*11038SRao.Shoaib@Sun.COM * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15*11038SRao.Shoaib@Sun.COM * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 160Sstevel@tonic-gate */ 170Sstevel@tonic-gate 180Sstevel@tonic-gate /* eventlib.c - implement glue for the eventlib 190Sstevel@tonic-gate * vix 09sep95 [initial] 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate 220Sstevel@tonic-gate #if !defined(LINT) && !defined(CODECENTER) 23*11038SRao.Shoaib@Sun.COM static const char rcsid[] = "$Id: eventlib.c,v 1.10 2006/03/09 23:57:56 marka Exp $"; 240Sstevel@tonic-gate #endif 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include "port_before.h" 270Sstevel@tonic-gate #include "fd_setsize.h" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <sys/types.h> 300Sstevel@tonic-gate #include <sys/time.h> 310Sstevel@tonic-gate #include <sys/stat.h> 32*11038SRao.Shoaib@Sun.COM #ifdef SOLARIS2 330Sstevel@tonic-gate #include <limits.h> 34*11038SRao.Shoaib@Sun.COM #endif /* SOLARIS2 */ 350Sstevel@tonic-gate 360Sstevel@tonic-gate #include <errno.h> 370Sstevel@tonic-gate #include <signal.h> 380Sstevel@tonic-gate #include <stdarg.h> 390Sstevel@tonic-gate #include <stdlib.h> 400Sstevel@tonic-gate #include <unistd.h> 410Sstevel@tonic-gate 420Sstevel@tonic-gate #include <isc/eventlib.h> 430Sstevel@tonic-gate #include <isc/assertions.h> 440Sstevel@tonic-gate #include "eventlib_p.h" 450Sstevel@tonic-gate 460Sstevel@tonic-gate #include "port_after.h" 470Sstevel@tonic-gate 48*11038SRao.Shoaib@Sun.COM int __evOptMonoTime; 49*11038SRao.Shoaib@Sun.COM 50*11038SRao.Shoaib@Sun.COM #ifdef USE_POLL 51*11038SRao.Shoaib@Sun.COM #define pselect Pselect 52*11038SRao.Shoaib@Sun.COM #endif /* USE_POLL */ 530Sstevel@tonic-gate 540Sstevel@tonic-gate /* Forward. */ 550Sstevel@tonic-gate 56*11038SRao.Shoaib@Sun.COM #if defined(NEED_PSELECT) || defined(USE_POLL) 570Sstevel@tonic-gate static int pselect(int, void *, void *, void *, 580Sstevel@tonic-gate struct timespec *, 590Sstevel@tonic-gate const sigset_t *); 600Sstevel@tonic-gate #endif 610Sstevel@tonic-gate 62*11038SRao.Shoaib@Sun.COM int __evOptMonoTime; 63*11038SRao.Shoaib@Sun.COM 640Sstevel@tonic-gate /* Public. */ 650Sstevel@tonic-gate 660Sstevel@tonic-gate int 670Sstevel@tonic-gate evCreate(evContext *opaqueCtx) { 680Sstevel@tonic-gate evContext_p *ctx; 690Sstevel@tonic-gate 700Sstevel@tonic-gate /* Make sure the memory heap is initialized. */ 710Sstevel@tonic-gate if (meminit(0, 0) < 0 && errno != EEXIST) 720Sstevel@tonic-gate return (-1); 730Sstevel@tonic-gate 740Sstevel@tonic-gate OKNEW(ctx); 750Sstevel@tonic-gate 760Sstevel@tonic-gate /* Global. */ 770Sstevel@tonic-gate ctx->cur = NULL; 780Sstevel@tonic-gate 790Sstevel@tonic-gate /* Debugging. */ 800Sstevel@tonic-gate ctx->debug = 0; 810Sstevel@tonic-gate ctx->output = NULL; 820Sstevel@tonic-gate 830Sstevel@tonic-gate /* Connections. */ 840Sstevel@tonic-gate ctx->conns = NULL; 850Sstevel@tonic-gate INIT_LIST(ctx->accepts); 860Sstevel@tonic-gate 870Sstevel@tonic-gate /* Files. */ 880Sstevel@tonic-gate ctx->files = NULL; 89*11038SRao.Shoaib@Sun.COM #ifdef USE_POLL 90*11038SRao.Shoaib@Sun.COM ctx->pollfds = NULL; 910Sstevel@tonic-gate ctx->maxnfds = 0; 920Sstevel@tonic-gate ctx->firstfd = 0; 930Sstevel@tonic-gate emulMaskInit(ctx, rdLast, EV_READ, 1); 940Sstevel@tonic-gate emulMaskInit(ctx, rdNext, EV_READ, 0); 950Sstevel@tonic-gate emulMaskInit(ctx, wrLast, EV_WRITE, 1); 960Sstevel@tonic-gate emulMaskInit(ctx, wrNext, EV_WRITE, 0); 970Sstevel@tonic-gate emulMaskInit(ctx, exLast, EV_EXCEPT, 1); 980Sstevel@tonic-gate emulMaskInit(ctx, exNext, EV_EXCEPT, 0); 990Sstevel@tonic-gate emulMaskInit(ctx, nonblockBefore, EV_WASNONBLOCKING, 0); 100*11038SRao.Shoaib@Sun.COM #endif /* USE_POLL */ 1010Sstevel@tonic-gate FD_ZERO(&ctx->rdNext); 1020Sstevel@tonic-gate FD_ZERO(&ctx->wrNext); 1030Sstevel@tonic-gate FD_ZERO(&ctx->exNext); 1040Sstevel@tonic-gate FD_ZERO(&ctx->nonblockBefore); 1050Sstevel@tonic-gate ctx->fdMax = -1; 1060Sstevel@tonic-gate ctx->fdNext = NULL; 107*11038SRao.Shoaib@Sun.COM ctx->fdCount = 0; /*%< Invalidate {rd,wr,ex}Last. */ 108*11038SRao.Shoaib@Sun.COM #ifndef USE_POLL 1090Sstevel@tonic-gate ctx->highestFD = FD_SETSIZE - 1; 110*11038SRao.Shoaib@Sun.COM memset(ctx->fdTable, 0, sizeof ctx->fdTable); 111*11038SRao.Shoaib@Sun.COM #else 112*11038SRao.Shoaib@Sun.COM ctx->highestFD = INT_MAX / sizeof(struct pollfd); 113*11038SRao.Shoaib@Sun.COM ctx->fdTable = NULL; 114*11038SRao.Shoaib@Sun.COM #endif /* USE_POLL */ 1150Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 1160Sstevel@tonic-gate ctx->lastFdCount = 0; 1170Sstevel@tonic-gate #endif 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate /* Streams. */ 1200Sstevel@tonic-gate ctx->streams = NULL; 1210Sstevel@tonic-gate ctx->strDone = NULL; 1220Sstevel@tonic-gate ctx->strLast = NULL; 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate /* Timers. */ 1250Sstevel@tonic-gate ctx->lastEventTime = evNowTime(); 1260Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 1270Sstevel@tonic-gate ctx->lastSelectTime = ctx->lastEventTime; 1280Sstevel@tonic-gate #endif 1290Sstevel@tonic-gate ctx->timers = evCreateTimers(ctx); 1300Sstevel@tonic-gate if (ctx->timers == NULL) 1310Sstevel@tonic-gate return (-1); 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate /* Waits. */ 1340Sstevel@tonic-gate ctx->waitLists = NULL; 1350Sstevel@tonic-gate ctx->waitDone.first = ctx->waitDone.last = NULL; 1360Sstevel@tonic-gate ctx->waitDone.prev = ctx->waitDone.next = NULL; 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate opaqueCtx->opaque = ctx; 1390Sstevel@tonic-gate return (0); 1400Sstevel@tonic-gate } 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate void 1430Sstevel@tonic-gate evSetDebug(evContext opaqueCtx, int level, FILE *output) { 1440Sstevel@tonic-gate evContext_p *ctx = opaqueCtx.opaque; 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate ctx->debug = level; 1470Sstevel@tonic-gate ctx->output = output; 1480Sstevel@tonic-gate } 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate int 1510Sstevel@tonic-gate evDestroy(evContext opaqueCtx) { 1520Sstevel@tonic-gate evContext_p *ctx = opaqueCtx.opaque; 153*11038SRao.Shoaib@Sun.COM int revs = 424242; /*%< Doug Adams. */ 1540Sstevel@tonic-gate evWaitList *this_wl, *next_wl; 1550Sstevel@tonic-gate evWait *this_wait, *next_wait; 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate /* Connections. */ 1580Sstevel@tonic-gate while (revs-- > 0 && ctx->conns != NULL) { 1590Sstevel@tonic-gate evConnID id; 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate id.opaque = ctx->conns; 1620Sstevel@tonic-gate (void) evCancelConn(opaqueCtx, id); 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate INSIST(revs >= 0); 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate /* Streams. */ 1670Sstevel@tonic-gate while (revs-- > 0 && ctx->streams != NULL) { 1680Sstevel@tonic-gate evStreamID id; 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate id.opaque = ctx->streams; 1710Sstevel@tonic-gate (void) evCancelRW(opaqueCtx, id); 1720Sstevel@tonic-gate } 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate /* Files. */ 1750Sstevel@tonic-gate while (revs-- > 0 && ctx->files != NULL) { 1760Sstevel@tonic-gate evFileID id; 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate id.opaque = ctx->files; 1790Sstevel@tonic-gate (void) evDeselectFD(opaqueCtx, id); 1800Sstevel@tonic-gate } 1810Sstevel@tonic-gate INSIST(revs >= 0); 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate /* Timers. */ 1840Sstevel@tonic-gate evDestroyTimers(ctx); 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate /* Waits. */ 1870Sstevel@tonic-gate for (this_wl = ctx->waitLists; 1880Sstevel@tonic-gate revs-- > 0 && this_wl != NULL; 1890Sstevel@tonic-gate this_wl = next_wl) { 1900Sstevel@tonic-gate next_wl = this_wl->next; 1910Sstevel@tonic-gate for (this_wait = this_wl->first; 1920Sstevel@tonic-gate revs-- > 0 && this_wait != NULL; 1930Sstevel@tonic-gate this_wait = next_wait) { 1940Sstevel@tonic-gate next_wait = this_wait->next; 1950Sstevel@tonic-gate FREE(this_wait); 1960Sstevel@tonic-gate } 1970Sstevel@tonic-gate FREE(this_wl); 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate for (this_wait = ctx->waitDone.first; 2000Sstevel@tonic-gate revs-- > 0 && this_wait != NULL; 2010Sstevel@tonic-gate this_wait = next_wait) { 2020Sstevel@tonic-gate next_wait = this_wait->next; 2030Sstevel@tonic-gate FREE(this_wait); 2040Sstevel@tonic-gate } 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate FREE(ctx); 2070Sstevel@tonic-gate return (0); 2080Sstevel@tonic-gate } 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate int 2110Sstevel@tonic-gate evGetNext(evContext opaqueCtx, evEvent *opaqueEv, int options) { 2120Sstevel@tonic-gate evContext_p *ctx = opaqueCtx.opaque; 2130Sstevel@tonic-gate struct timespec nextTime; 2140Sstevel@tonic-gate evTimer *nextTimer; 2150Sstevel@tonic-gate evEvent_p *new; 2160Sstevel@tonic-gate int x, pselect_errno, timerPast; 2170Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 2180Sstevel@tonic-gate struct timespec interval; 2190Sstevel@tonic-gate #endif 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate /* Ensure that exactly one of EV_POLL or EV_WAIT was specified. */ 2220Sstevel@tonic-gate x = ((options & EV_POLL) != 0) + ((options & EV_WAIT) != 0); 2230Sstevel@tonic-gate if (x != 1) 2240Sstevel@tonic-gate EV_ERR(EINVAL); 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate /* Get the time of day. We'll do this again after select() blocks. */ 2270Sstevel@tonic-gate ctx->lastEventTime = evNowTime(); 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate again: 2300Sstevel@tonic-gate /* Finished accept()'s do not require a select(). */ 2310Sstevel@tonic-gate if (!EMPTY(ctx->accepts)) { 2320Sstevel@tonic-gate OKNEW(new); 2330Sstevel@tonic-gate new->type = Accept; 2340Sstevel@tonic-gate new->u.accept.this = HEAD(ctx->accepts); 2350Sstevel@tonic-gate UNLINK(ctx->accepts, HEAD(ctx->accepts), link); 2360Sstevel@tonic-gate opaqueEv->opaque = new; 2370Sstevel@tonic-gate return (0); 2380Sstevel@tonic-gate } 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate /* Stream IO does not require a select(). */ 2410Sstevel@tonic-gate if (ctx->strDone != NULL) { 2420Sstevel@tonic-gate OKNEW(new); 2430Sstevel@tonic-gate new->type = Stream; 2440Sstevel@tonic-gate new->u.stream.this = ctx->strDone; 2450Sstevel@tonic-gate ctx->strDone = ctx->strDone->nextDone; 2460Sstevel@tonic-gate if (ctx->strDone == NULL) 2470Sstevel@tonic-gate ctx->strLast = NULL; 2480Sstevel@tonic-gate opaqueEv->opaque = new; 2490Sstevel@tonic-gate return (0); 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate /* Waits do not require a select(). */ 2530Sstevel@tonic-gate if (ctx->waitDone.first != NULL) { 2540Sstevel@tonic-gate OKNEW(new); 2550Sstevel@tonic-gate new->type = Wait; 2560Sstevel@tonic-gate new->u.wait.this = ctx->waitDone.first; 2570Sstevel@tonic-gate ctx->waitDone.first = ctx->waitDone.first->next; 2580Sstevel@tonic-gate if (ctx->waitDone.first == NULL) 2590Sstevel@tonic-gate ctx->waitDone.last = NULL; 2600Sstevel@tonic-gate opaqueEv->opaque = new; 2610Sstevel@tonic-gate return (0); 2620Sstevel@tonic-gate } 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate /* Get the status and content of the next timer. */ 2650Sstevel@tonic-gate if ((nextTimer = heap_element(ctx->timers, 1)) != NULL) { 2660Sstevel@tonic-gate nextTime = nextTimer->due; 2670Sstevel@tonic-gate timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0); 2680Sstevel@tonic-gate } else 269*11038SRao.Shoaib@Sun.COM timerPast = 0; /*%< Make gcc happy. */ 2700Sstevel@tonic-gate evPrintf(ctx, 9, "evGetNext: fdCount %d\n", ctx->fdCount); 2710Sstevel@tonic-gate if (ctx->fdCount == 0) { 2720Sstevel@tonic-gate static const struct timespec NoTime = {0, 0L}; 2730Sstevel@tonic-gate enum { JustPoll, Block, Timer } m; 2740Sstevel@tonic-gate struct timespec t, *tp; 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate /* Are there any events at all? */ 2770Sstevel@tonic-gate if ((options & EV_WAIT) != 0 && !nextTimer && ctx->fdMax == -1) 2780Sstevel@tonic-gate EV_ERR(ENOENT); 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate /* Figure out what select()'s timeout parameter should be. */ 2810Sstevel@tonic-gate if ((options & EV_POLL) != 0) { 2820Sstevel@tonic-gate m = JustPoll; 2830Sstevel@tonic-gate t = NoTime; 2840Sstevel@tonic-gate tp = &t; 2850Sstevel@tonic-gate } else if (nextTimer == NULL) { 2860Sstevel@tonic-gate m = Block; 2870Sstevel@tonic-gate /* ``t'' unused. */ 2880Sstevel@tonic-gate tp = NULL; 2890Sstevel@tonic-gate } else if (timerPast) { 2900Sstevel@tonic-gate m = JustPoll; 2910Sstevel@tonic-gate t = NoTime; 2920Sstevel@tonic-gate tp = &t; 2930Sstevel@tonic-gate } else { 2940Sstevel@tonic-gate m = Timer; 2950Sstevel@tonic-gate /* ``t'' filled in later. */ 2960Sstevel@tonic-gate tp = &t; 2970Sstevel@tonic-gate } 2980Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 2990Sstevel@tonic-gate if (ctx->debug > 0) { 3000Sstevel@tonic-gate interval = evSubTime(ctx->lastEventTime, 3010Sstevel@tonic-gate ctx->lastSelectTime); 302*11038SRao.Shoaib@Sun.COM if (interval.tv_sec > 0 || interval.tv_nsec > 0) 3030Sstevel@tonic-gate evPrintf(ctx, 1, 3040Sstevel@tonic-gate "time between pselect() %u.%09u count %d\n", 3050Sstevel@tonic-gate interval.tv_sec, interval.tv_nsec, 3060Sstevel@tonic-gate ctx->lastFdCount); 3070Sstevel@tonic-gate } 3080Sstevel@tonic-gate #endif 3090Sstevel@tonic-gate do { 310*11038SRao.Shoaib@Sun.COM #ifndef USE_POLL 311*11038SRao.Shoaib@Sun.COM /* XXX need to copy only the bits we are using. */ 312*11038SRao.Shoaib@Sun.COM ctx->rdLast = ctx->rdNext; 313*11038SRao.Shoaib@Sun.COM ctx->wrLast = ctx->wrNext; 314*11038SRao.Shoaib@Sun.COM ctx->exLast = ctx->exNext; 315*11038SRao.Shoaib@Sun.COM #else 3160Sstevel@tonic-gate /* 3170Sstevel@tonic-gate * The pollfd structure uses separate fields for 3180Sstevel@tonic-gate * the input and output events (corresponding to 3190Sstevel@tonic-gate * the ??Next and ??Last fd sets), so there's no 3200Sstevel@tonic-gate * need to copy one to the other. 3210Sstevel@tonic-gate */ 322*11038SRao.Shoaib@Sun.COM #endif /* USE_POLL */ 3230Sstevel@tonic-gate if (m == Timer) { 3240Sstevel@tonic-gate INSIST(tp == &t); 3250Sstevel@tonic-gate t = evSubTime(nextTime, ctx->lastEventTime); 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate /* XXX should predict system's earliness and adjust. */ 3290Sstevel@tonic-gate x = pselect(ctx->fdMax+1, 3300Sstevel@tonic-gate &ctx->rdLast, &ctx->wrLast, &ctx->exLast, 3310Sstevel@tonic-gate tp, NULL); 3320Sstevel@tonic-gate pselect_errno = errno; 3330Sstevel@tonic-gate 334*11038SRao.Shoaib@Sun.COM #ifndef USE_POLL 335*11038SRao.Shoaib@Sun.COM evPrintf(ctx, 4, "select() returns %d (err: %s)\n", 3360Sstevel@tonic-gate x, (x == -1) ? strerror(errno) : "none"); 3370Sstevel@tonic-gate #else 338*11038SRao.Shoaib@Sun.COM evPrintf(ctx, 4, "poll() returns %d (err: %s)\n", 339*11038SRao.Shoaib@Sun.COM x, (x == -1) ? strerror(errno) : "none"); 340*11038SRao.Shoaib@Sun.COM #endif /* USE_POLL */ 3410Sstevel@tonic-gate /* Anything but a poll can change the time. */ 3420Sstevel@tonic-gate if (m != JustPoll) 3430Sstevel@tonic-gate ctx->lastEventTime = evNowTime(); 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate /* Select() likes to finish about 10ms early. */ 3460Sstevel@tonic-gate } while (x == 0 && m == Timer && 3470Sstevel@tonic-gate evCmpTime(ctx->lastEventTime, nextTime) < 0); 3480Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 3490Sstevel@tonic-gate ctx->lastSelectTime = ctx->lastEventTime; 3500Sstevel@tonic-gate #endif 3510Sstevel@tonic-gate if (x < 0) { 3520Sstevel@tonic-gate if (pselect_errno == EINTR) { 3530Sstevel@tonic-gate if ((options & EV_NULL) != 0) 3540Sstevel@tonic-gate goto again; 3550Sstevel@tonic-gate OKNEW(new); 3560Sstevel@tonic-gate new->type = Null; 3570Sstevel@tonic-gate /* No data. */ 3580Sstevel@tonic-gate opaqueEv->opaque = new; 3590Sstevel@tonic-gate return (0); 3600Sstevel@tonic-gate } 3610Sstevel@tonic-gate if (pselect_errno == EBADF) { 3620Sstevel@tonic-gate for (x = 0; x <= ctx->fdMax; x++) { 3630Sstevel@tonic-gate struct stat sb; 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate if (FD_ISSET(x, &ctx->rdNext) == 0 && 3660Sstevel@tonic-gate FD_ISSET(x, &ctx->wrNext) == 0 && 3670Sstevel@tonic-gate FD_ISSET(x, &ctx->exNext) == 0) 3680Sstevel@tonic-gate continue; 3690Sstevel@tonic-gate if (fstat(x, &sb) == -1 && 3700Sstevel@tonic-gate errno == EBADF) 3710Sstevel@tonic-gate evPrintf(ctx, 1, "EBADF: %d\n", 3720Sstevel@tonic-gate x); 3730Sstevel@tonic-gate } 3740Sstevel@tonic-gate abort(); 3750Sstevel@tonic-gate } 3760Sstevel@tonic-gate EV_ERR(pselect_errno); 3770Sstevel@tonic-gate } 3780Sstevel@tonic-gate if (x == 0 && (nextTimer == NULL || !timerPast) && 3790Sstevel@tonic-gate (options & EV_POLL)) 3800Sstevel@tonic-gate EV_ERR(EWOULDBLOCK); 3810Sstevel@tonic-gate ctx->fdCount = x; 3820Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 3830Sstevel@tonic-gate ctx->lastFdCount = x; 3840Sstevel@tonic-gate #endif 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate INSIST(nextTimer || ctx->fdCount); 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate /* Timers go first since we'd like them to be accurate. */ 3890Sstevel@tonic-gate if (nextTimer && !timerPast) { 3900Sstevel@tonic-gate /* Has anything happened since we blocked? */ 3910Sstevel@tonic-gate timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0); 3920Sstevel@tonic-gate } 3930Sstevel@tonic-gate if (nextTimer && timerPast) { 3940Sstevel@tonic-gate OKNEW(new); 3950Sstevel@tonic-gate new->type = Timer; 3960Sstevel@tonic-gate new->u.timer.this = nextTimer; 3970Sstevel@tonic-gate opaqueEv->opaque = new; 3980Sstevel@tonic-gate return (0); 3990Sstevel@tonic-gate } 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate /* No timers, so there should be a ready file descriptor. */ 4020Sstevel@tonic-gate x = 0; 4030Sstevel@tonic-gate while (ctx->fdCount > 0) { 4040Sstevel@tonic-gate evFile *fid; 4050Sstevel@tonic-gate int fd, eventmask; 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate if (ctx->fdNext == NULL) { 4080Sstevel@tonic-gate if (++x == 2) { 4090Sstevel@tonic-gate /* 4100Sstevel@tonic-gate * Hitting the end twice means that the last 4110Sstevel@tonic-gate * select() found some FD's which have since 4120Sstevel@tonic-gate * been deselected. 4130Sstevel@tonic-gate * 4140Sstevel@tonic-gate * On some systems, the count returned by 4150Sstevel@tonic-gate * selects is the total number of bits in 4160Sstevel@tonic-gate * all masks that are set, and on others it's 4170Sstevel@tonic-gate * the number of fd's that have some bit set, 4180Sstevel@tonic-gate * and on others, it's just broken. We 4190Sstevel@tonic-gate * always assume that it's the number of 4200Sstevel@tonic-gate * bits set in all masks, because that's what 4210Sstevel@tonic-gate * the man page says it should do, and 4220Sstevel@tonic-gate * the worst that can happen is we do an 4230Sstevel@tonic-gate * extra select(). 4240Sstevel@tonic-gate */ 4250Sstevel@tonic-gate ctx->fdCount = 0; 4260Sstevel@tonic-gate break; 4270Sstevel@tonic-gate } 4280Sstevel@tonic-gate ctx->fdNext = ctx->files; 4290Sstevel@tonic-gate } 4300Sstevel@tonic-gate fid = ctx->fdNext; 4310Sstevel@tonic-gate ctx->fdNext = fid->next; 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate fd = fid->fd; 4340Sstevel@tonic-gate eventmask = 0; 4350Sstevel@tonic-gate if (FD_ISSET(fd, &ctx->rdLast)) 4360Sstevel@tonic-gate eventmask |= EV_READ; 4370Sstevel@tonic-gate if (FD_ISSET(fd, &ctx->wrLast)) 4380Sstevel@tonic-gate eventmask |= EV_WRITE; 4390Sstevel@tonic-gate if (FD_ISSET(fd, &ctx->exLast)) 4400Sstevel@tonic-gate eventmask |= EV_EXCEPT; 4410Sstevel@tonic-gate eventmask &= fid->eventmask; 4420Sstevel@tonic-gate if (eventmask != 0) { 4430Sstevel@tonic-gate if ((eventmask & EV_READ) != 0) { 4440Sstevel@tonic-gate FD_CLR(fd, &ctx->rdLast); 4450Sstevel@tonic-gate ctx->fdCount--; 4460Sstevel@tonic-gate } 4470Sstevel@tonic-gate if ((eventmask & EV_WRITE) != 0) { 4480Sstevel@tonic-gate FD_CLR(fd, &ctx->wrLast); 4490Sstevel@tonic-gate ctx->fdCount--; 4500Sstevel@tonic-gate } 4510Sstevel@tonic-gate if ((eventmask & EV_EXCEPT) != 0) { 4520Sstevel@tonic-gate FD_CLR(fd, &ctx->exLast); 4530Sstevel@tonic-gate ctx->fdCount--; 4540Sstevel@tonic-gate } 4550Sstevel@tonic-gate OKNEW(new); 4560Sstevel@tonic-gate new->type = File; 4570Sstevel@tonic-gate new->u.file.this = fid; 4580Sstevel@tonic-gate new->u.file.eventmask = eventmask; 4590Sstevel@tonic-gate opaqueEv->opaque = new; 4600Sstevel@tonic-gate return (0); 4610Sstevel@tonic-gate } 4620Sstevel@tonic-gate } 4630Sstevel@tonic-gate if (ctx->fdCount < 0) { 4640Sstevel@tonic-gate /* 4650Sstevel@tonic-gate * select()'s count is off on a number of systems, and 4660Sstevel@tonic-gate * can result in fdCount < 0. 4670Sstevel@tonic-gate */ 4680Sstevel@tonic-gate evPrintf(ctx, 4, "fdCount < 0 (%d)\n", ctx->fdCount); 4690Sstevel@tonic-gate ctx->fdCount = 0; 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate /* We get here if the caller deselect()'s an FD. Gag me with a goto. */ 4730Sstevel@tonic-gate goto again; 4740Sstevel@tonic-gate } 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate int 4770Sstevel@tonic-gate evDispatch(evContext opaqueCtx, evEvent opaqueEv) { 4780Sstevel@tonic-gate evContext_p *ctx = opaqueCtx.opaque; 4790Sstevel@tonic-gate evEvent_p *ev = opaqueEv.opaque; 4800Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 4810Sstevel@tonic-gate void *func; 4820Sstevel@tonic-gate struct timespec start_time; 4830Sstevel@tonic-gate struct timespec interval; 4840Sstevel@tonic-gate #endif 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 4870Sstevel@tonic-gate if (ctx->debug > 0) 4880Sstevel@tonic-gate start_time = evNowTime(); 4890Sstevel@tonic-gate #endif 4900Sstevel@tonic-gate ctx->cur = ev; 4910Sstevel@tonic-gate switch (ev->type) { 4920Sstevel@tonic-gate case Accept: { 4930Sstevel@tonic-gate evAccept *this = ev->u.accept.this; 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate evPrintf(ctx, 5, 4960Sstevel@tonic-gate "Dispatch.Accept: fd %d -> %d, func %p, uap %p\n", 4970Sstevel@tonic-gate this->conn->fd, this->fd, 4980Sstevel@tonic-gate this->conn->func, this->conn->uap); 4990Sstevel@tonic-gate errno = this->ioErrno; 5000Sstevel@tonic-gate (this->conn->func)(opaqueCtx, this->conn->uap, this->fd, 5010Sstevel@tonic-gate &this->la, this->lalen, 5020Sstevel@tonic-gate &this->ra, this->ralen); 5030Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 5040Sstevel@tonic-gate func = this->conn->func; 5050Sstevel@tonic-gate #endif 5060Sstevel@tonic-gate break; 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate case File: { 5090Sstevel@tonic-gate evFile *this = ev->u.file.this; 5100Sstevel@tonic-gate int eventmask = ev->u.file.eventmask; 5110Sstevel@tonic-gate 5120Sstevel@tonic-gate evPrintf(ctx, 5, 5130Sstevel@tonic-gate "Dispatch.File: fd %d, mask 0x%x, func %p, uap %p\n", 5140Sstevel@tonic-gate this->fd, this->eventmask, this->func, this->uap); 5150Sstevel@tonic-gate (this->func)(opaqueCtx, this->uap, this->fd, eventmask); 5160Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 5170Sstevel@tonic-gate func = this->func; 5180Sstevel@tonic-gate #endif 5190Sstevel@tonic-gate break; 5200Sstevel@tonic-gate } 5210Sstevel@tonic-gate case Stream: { 5220Sstevel@tonic-gate evStream *this = ev->u.stream.this; 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate evPrintf(ctx, 5, 5250Sstevel@tonic-gate "Dispatch.Stream: fd %d, func %p, uap %p\n", 5260Sstevel@tonic-gate this->fd, this->func, this->uap); 5270Sstevel@tonic-gate errno = this->ioErrno; 5280Sstevel@tonic-gate (this->func)(opaqueCtx, this->uap, this->fd, this->ioDone); 5290Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 5300Sstevel@tonic-gate func = this->func; 5310Sstevel@tonic-gate #endif 5320Sstevel@tonic-gate break; 5330Sstevel@tonic-gate } 5340Sstevel@tonic-gate case Timer: { 5350Sstevel@tonic-gate evTimer *this = ev->u.timer.this; 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate evPrintf(ctx, 5, "Dispatch.Timer: func %p, uap %p\n", 5380Sstevel@tonic-gate this->func, this->uap); 5390Sstevel@tonic-gate (this->func)(opaqueCtx, this->uap, this->due, this->inter); 5400Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 5410Sstevel@tonic-gate func = this->func; 5420Sstevel@tonic-gate #endif 5430Sstevel@tonic-gate break; 5440Sstevel@tonic-gate } 5450Sstevel@tonic-gate case Wait: { 5460Sstevel@tonic-gate evWait *this = ev->u.wait.this; 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate evPrintf(ctx, 5, 5490Sstevel@tonic-gate "Dispatch.Wait: tag %p, func %p, uap %p\n", 5500Sstevel@tonic-gate this->tag, this->func, this->uap); 5510Sstevel@tonic-gate (this->func)(opaqueCtx, this->uap, this->tag); 5520Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 5530Sstevel@tonic-gate func = this->func; 5540Sstevel@tonic-gate #endif 5550Sstevel@tonic-gate break; 5560Sstevel@tonic-gate } 5570Sstevel@tonic-gate case Null: { 5580Sstevel@tonic-gate /* No work. */ 5590Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 5600Sstevel@tonic-gate func = NULL; 5610Sstevel@tonic-gate #endif 5620Sstevel@tonic-gate break; 5630Sstevel@tonic-gate } 5640Sstevel@tonic-gate default: { 5650Sstevel@tonic-gate abort(); 5660Sstevel@tonic-gate } 5670Sstevel@tonic-gate } 5680Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS 5690Sstevel@tonic-gate if (ctx->debug > 0) { 5700Sstevel@tonic-gate interval = evSubTime(evNowTime(), start_time); 5710Sstevel@tonic-gate /* 5720Sstevel@tonic-gate * Complain if it took longer than 50 milliseconds. 5730Sstevel@tonic-gate * 5740Sstevel@tonic-gate * We call getuid() to make an easy to find mark in a kernel 5750Sstevel@tonic-gate * trace. 5760Sstevel@tonic-gate */ 5770Sstevel@tonic-gate if (interval.tv_sec > 0 || interval.tv_nsec > 50000000) 5780Sstevel@tonic-gate evPrintf(ctx, 1, 5790Sstevel@tonic-gate "dispatch interval %u.%09u uid %d type %d func %p\n", 5800Sstevel@tonic-gate interval.tv_sec, interval.tv_nsec, 5810Sstevel@tonic-gate getuid(), ev->type, func); 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate #endif 5840Sstevel@tonic-gate ctx->cur = NULL; 5850Sstevel@tonic-gate evDrop(opaqueCtx, opaqueEv); 5860Sstevel@tonic-gate return (0); 5870Sstevel@tonic-gate } 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate void 5900Sstevel@tonic-gate evDrop(evContext opaqueCtx, evEvent opaqueEv) { 5910Sstevel@tonic-gate evContext_p *ctx = opaqueCtx.opaque; 5920Sstevel@tonic-gate evEvent_p *ev = opaqueEv.opaque; 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate switch (ev->type) { 5950Sstevel@tonic-gate case Accept: { 5960Sstevel@tonic-gate FREE(ev->u.accept.this); 5970Sstevel@tonic-gate break; 5980Sstevel@tonic-gate } 5990Sstevel@tonic-gate case File: { 6000Sstevel@tonic-gate /* No work. */ 6010Sstevel@tonic-gate break; 6020Sstevel@tonic-gate } 6030Sstevel@tonic-gate case Stream: { 6040Sstevel@tonic-gate evStreamID id; 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate id.opaque = ev->u.stream.this; 6070Sstevel@tonic-gate (void) evCancelRW(opaqueCtx, id); 6080Sstevel@tonic-gate break; 6090Sstevel@tonic-gate } 6100Sstevel@tonic-gate case Timer: { 6110Sstevel@tonic-gate evTimer *this = ev->u.timer.this; 6120Sstevel@tonic-gate evTimerID opaque; 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate /* Check to see whether the user func cleared the timer. */ 6150Sstevel@tonic-gate if (heap_element(ctx->timers, this->index) != this) { 6160Sstevel@tonic-gate evPrintf(ctx, 5, "Dispatch.Timer: timer rm'd?\n"); 6170Sstevel@tonic-gate break; 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate /* 6200Sstevel@tonic-gate * Timer is still there. Delete it if it has expired, 6210Sstevel@tonic-gate * otherwise set it according to its next interval. 6220Sstevel@tonic-gate */ 623*11038SRao.Shoaib@Sun.COM if (this->inter.tv_sec == (time_t)0 && 624*11038SRao.Shoaib@Sun.COM this->inter.tv_nsec == 0L) { 6250Sstevel@tonic-gate opaque.opaque = this; 6260Sstevel@tonic-gate (void) evClearTimer(opaqueCtx, opaque); 6270Sstevel@tonic-gate } else { 6280Sstevel@tonic-gate opaque.opaque = this; 6290Sstevel@tonic-gate (void) evResetTimer(opaqueCtx, opaque, this->func, 6300Sstevel@tonic-gate this->uap, 631*11038SRao.Shoaib@Sun.COM evAddTime((this->mode & EV_TMR_RATE) ? 632*11038SRao.Shoaib@Sun.COM this->due : 633*11038SRao.Shoaib@Sun.COM ctx->lastEventTime, 6340Sstevel@tonic-gate this->inter), 6350Sstevel@tonic-gate this->inter); 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate break; 6380Sstevel@tonic-gate } 6390Sstevel@tonic-gate case Wait: { 6400Sstevel@tonic-gate FREE(ev->u.wait.this); 6410Sstevel@tonic-gate break; 6420Sstevel@tonic-gate } 6430Sstevel@tonic-gate case Null: { 6440Sstevel@tonic-gate /* No work. */ 6450Sstevel@tonic-gate break; 6460Sstevel@tonic-gate } 6470Sstevel@tonic-gate default: { 6480Sstevel@tonic-gate abort(); 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate } 6510Sstevel@tonic-gate FREE(ev); 6520Sstevel@tonic-gate } 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate int 6550Sstevel@tonic-gate evMainLoop(evContext opaqueCtx) { 6560Sstevel@tonic-gate evEvent event; 6570Sstevel@tonic-gate int x; 6580Sstevel@tonic-gate 6590Sstevel@tonic-gate while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0) 6600Sstevel@tonic-gate if ((x = evDispatch(opaqueCtx, event)) < 0) 6610Sstevel@tonic-gate break; 6620Sstevel@tonic-gate return (x); 6630Sstevel@tonic-gate } 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate int 6660Sstevel@tonic-gate evHighestFD(evContext opaqueCtx) { 6670Sstevel@tonic-gate evContext_p *ctx = opaqueCtx.opaque; 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate return (ctx->highestFD); 6700Sstevel@tonic-gate } 6710Sstevel@tonic-gate 6720Sstevel@tonic-gate void 6730Sstevel@tonic-gate evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) { 6740Sstevel@tonic-gate va_list ap; 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate va_start(ap, fmt); 6770Sstevel@tonic-gate if (ctx->output != NULL && ctx->debug >= level) { 6780Sstevel@tonic-gate vfprintf(ctx->output, fmt, ap); 6790Sstevel@tonic-gate fflush(ctx->output); 6800Sstevel@tonic-gate } 6810Sstevel@tonic-gate va_end(ap); 6820Sstevel@tonic-gate } 6830Sstevel@tonic-gate 684*11038SRao.Shoaib@Sun.COM int 685*11038SRao.Shoaib@Sun.COM evSetOption(evContext *opaqueCtx, const char *option, int value) { 686*11038SRao.Shoaib@Sun.COM /* evContext_p *ctx = opaqueCtx->opaque; */ 687*11038SRao.Shoaib@Sun.COM 688*11038SRao.Shoaib@Sun.COM UNUSED(opaqueCtx); 689*11038SRao.Shoaib@Sun.COM UNUSED(value); 690*11038SRao.Shoaib@Sun.COM #ifndef CLOCK_MONOTONIC 691*11038SRao.Shoaib@Sun.COM UNUSED(option); 692*11038SRao.Shoaib@Sun.COM #endif 693*11038SRao.Shoaib@Sun.COM 694*11038SRao.Shoaib@Sun.COM #ifdef CLOCK_MONOTONIC 695*11038SRao.Shoaib@Sun.COM if (strcmp(option, "monotime") == 0) { 696*11038SRao.Shoaib@Sun.COM if (opaqueCtx != NULL) 697*11038SRao.Shoaib@Sun.COM errno = EINVAL; 698*11038SRao.Shoaib@Sun.COM if (value == 0 || value == 1) { 699*11038SRao.Shoaib@Sun.COM __evOptMonoTime = value; 700*11038SRao.Shoaib@Sun.COM return (0); 701*11038SRao.Shoaib@Sun.COM } else { 702*11038SRao.Shoaib@Sun.COM errno = EINVAL; 703*11038SRao.Shoaib@Sun.COM return (-1); 704*11038SRao.Shoaib@Sun.COM } 705*11038SRao.Shoaib@Sun.COM } 706*11038SRao.Shoaib@Sun.COM #endif 707*11038SRao.Shoaib@Sun.COM errno = ENOENT; 708*11038SRao.Shoaib@Sun.COM return (-1); 709*11038SRao.Shoaib@Sun.COM } 710*11038SRao.Shoaib@Sun.COM 711*11038SRao.Shoaib@Sun.COM int 712*11038SRao.Shoaib@Sun.COM evGetOption(evContext *opaqueCtx, const char *option, int *value) { 713*11038SRao.Shoaib@Sun.COM /* evContext_p *ctx = opaqueCtx->opaque; */ 714*11038SRao.Shoaib@Sun.COM 715*11038SRao.Shoaib@Sun.COM UNUSED(opaqueCtx); 716*11038SRao.Shoaib@Sun.COM #ifndef CLOCK_MONOTONIC 717*11038SRao.Shoaib@Sun.COM UNUSED(value); 718*11038SRao.Shoaib@Sun.COM UNUSED(option); 719*11038SRao.Shoaib@Sun.COM #endif 720*11038SRao.Shoaib@Sun.COM 721*11038SRao.Shoaib@Sun.COM #ifdef CLOCK_MONOTONIC 722*11038SRao.Shoaib@Sun.COM if (strcmp(option, "monotime") == 0) { 723*11038SRao.Shoaib@Sun.COM if (opaqueCtx != NULL) 724*11038SRao.Shoaib@Sun.COM errno = EINVAL; 725*11038SRao.Shoaib@Sun.COM *value = __evOptMonoTime; 726*11038SRao.Shoaib@Sun.COM return (0); 727*11038SRao.Shoaib@Sun.COM } 728*11038SRao.Shoaib@Sun.COM #endif 729*11038SRao.Shoaib@Sun.COM errno = ENOENT; 730*11038SRao.Shoaib@Sun.COM return (-1); 731*11038SRao.Shoaib@Sun.COM } 732*11038SRao.Shoaib@Sun.COM 733*11038SRao.Shoaib@Sun.COM #if defined(NEED_PSELECT) || defined(USE_POLL) 7340Sstevel@tonic-gate /* XXX needs to move to the porting library. */ 7350Sstevel@tonic-gate static int 7360Sstevel@tonic-gate pselect(int nfds, void *rfds, void *wfds, void *efds, 7370Sstevel@tonic-gate struct timespec *tsp, 7380Sstevel@tonic-gate const sigset_t *sigmask) 7390Sstevel@tonic-gate { 7400Sstevel@tonic-gate struct timeval tv, *tvp; 7410Sstevel@tonic-gate sigset_t sigs; 7420Sstevel@tonic-gate int n; 743*11038SRao.Shoaib@Sun.COM #ifdef USE_POLL 744*11038SRao.Shoaib@Sun.COM int polltimeout = INFTIM; 7450Sstevel@tonic-gate evContext_p *ctx; 7460Sstevel@tonic-gate struct pollfd *fds; 7470Sstevel@tonic-gate nfds_t pnfds; 748*11038SRao.Shoaib@Sun.COM 749*11038SRao.Shoaib@Sun.COM UNUSED(nfds); 750*11038SRao.Shoaib@Sun.COM #endif /* USE_POLL */ 7510Sstevel@tonic-gate 7520Sstevel@tonic-gate if (tsp) { 7530Sstevel@tonic-gate tvp = &tv; 7540Sstevel@tonic-gate tv = evTimeVal(*tsp); 755*11038SRao.Shoaib@Sun.COM #ifdef USE_POLL 756*11038SRao.Shoaib@Sun.COM polltimeout = 1000 * tv.tv_sec + tv.tv_usec / 1000; 757*11038SRao.Shoaib@Sun.COM #endif /* USE_POLL */ 7580Sstevel@tonic-gate } else 7590Sstevel@tonic-gate tvp = NULL; 7600Sstevel@tonic-gate if (sigmask) 7610Sstevel@tonic-gate sigprocmask(SIG_SETMASK, sigmask, &sigs); 762*11038SRao.Shoaib@Sun.COM #ifndef USE_POLL 763*11038SRao.Shoaib@Sun.COM n = select(nfds, rfds, wfds, efds, tvp); 764*11038SRao.Shoaib@Sun.COM #else 765*11038SRao.Shoaib@Sun.COM /* 7660Sstevel@tonic-gate * rfds, wfds, and efds should all be from the same evContext_p, 7670Sstevel@tonic-gate * so any of them will do. If they're all NULL, the caller is 7680Sstevel@tonic-gate * presumably calling us to block. 7690Sstevel@tonic-gate */ 770*11038SRao.Shoaib@Sun.COM if (rfds != NULL) 7710Sstevel@tonic-gate ctx = ((__evEmulMask *)rfds)->ctx; 772*11038SRao.Shoaib@Sun.COM else if (wfds != NULL) 7730Sstevel@tonic-gate ctx = ((__evEmulMask *)wfds)->ctx; 774*11038SRao.Shoaib@Sun.COM else if (efds != NULL) 7750Sstevel@tonic-gate ctx = ((__evEmulMask *)efds)->ctx; 7760Sstevel@tonic-gate else 777*11038SRao.Shoaib@Sun.COM ctx = NULL; 778*11038SRao.Shoaib@Sun.COM if (ctx != NULL && ctx->fdMax != -1) { 7790Sstevel@tonic-gate fds = &(ctx->pollfds[ctx->firstfd]); 7800Sstevel@tonic-gate pnfds = ctx->fdMax - ctx->firstfd + 1; 7810Sstevel@tonic-gate } else { 782*11038SRao.Shoaib@Sun.COM fds = NULL; 7830Sstevel@tonic-gate pnfds = 0; 7840Sstevel@tonic-gate } 7850Sstevel@tonic-gate n = poll(fds, pnfds, polltimeout); 7860Sstevel@tonic-gate if (n > 0) { 787*11038SRao.Shoaib@Sun.COM int i, e; 788*11038SRao.Shoaib@Sun.COM 789*11038SRao.Shoaib@Sun.COM INSIST(ctx != NULL); 7900Sstevel@tonic-gate for (e = 0, i = ctx->firstfd; i <= ctx->fdMax; i++) { 7910Sstevel@tonic-gate if (ctx->pollfds[i].fd < 0) 7920Sstevel@tonic-gate continue; 7930Sstevel@tonic-gate if (FD_ISSET(i, &ctx->rdLast)) 7940Sstevel@tonic-gate e++; 7950Sstevel@tonic-gate if (FD_ISSET(i, &ctx->wrLast)) 7960Sstevel@tonic-gate e++; 7970Sstevel@tonic-gate if (FD_ISSET(i, &ctx->exLast)) 7980Sstevel@tonic-gate e++; 7990Sstevel@tonic-gate } 8000Sstevel@tonic-gate n = e; 8010Sstevel@tonic-gate } 802*11038SRao.Shoaib@Sun.COM #endif /* USE_POLL */ 8030Sstevel@tonic-gate if (sigmask) 8040Sstevel@tonic-gate sigprocmask(SIG_SETMASK, &sigs, NULL); 8050Sstevel@tonic-gate if (tsp) 8060Sstevel@tonic-gate *tsp = evTimeSpec(tv); 8070Sstevel@tonic-gate return (n); 8080Sstevel@tonic-gate } 8090Sstevel@tonic-gate #endif 8100Sstevel@tonic-gate 811*11038SRao.Shoaib@Sun.COM #ifdef USE_POLL 812*11038SRao.Shoaib@Sun.COM int 8130Sstevel@tonic-gate evPollfdRealloc(evContext_p *ctx, int pollfd_chunk_size, int fd) { 814*11038SRao.Shoaib@Sun.COM 815*11038SRao.Shoaib@Sun.COM int i, maxnfds; 816*11038SRao.Shoaib@Sun.COM void *pollfds, *fdTable; 817*11038SRao.Shoaib@Sun.COM 818*11038SRao.Shoaib@Sun.COM if (fd < ctx->maxnfds) 819*11038SRao.Shoaib@Sun.COM return (0); 820*11038SRao.Shoaib@Sun.COM 8210Sstevel@tonic-gate /* Don't allow ridiculously small values for pollfd_chunk_size */ 8220Sstevel@tonic-gate if (pollfd_chunk_size < 20) 8230Sstevel@tonic-gate pollfd_chunk_size = 20; 824*11038SRao.Shoaib@Sun.COM 825*11038SRao.Shoaib@Sun.COM maxnfds = (1 + (fd/pollfd_chunk_size)) * pollfd_chunk_size; 826*11038SRao.Shoaib@Sun.COM 827*11038SRao.Shoaib@Sun.COM pollfds = realloc(ctx->pollfds, maxnfds * sizeof(*ctx->pollfds)); 828*11038SRao.Shoaib@Sun.COM if (pollfds != NULL) 829*11038SRao.Shoaib@Sun.COM ctx->pollfds = pollfds; 830*11038SRao.Shoaib@Sun.COM fdTable = realloc(ctx->fdTable, maxnfds * sizeof(*ctx->fdTable)); 831*11038SRao.Shoaib@Sun.COM if (fdTable != NULL) 832*11038SRao.Shoaib@Sun.COM ctx->fdTable = fdTable; 833*11038SRao.Shoaib@Sun.COM 834*11038SRao.Shoaib@Sun.COM if (pollfds == NULL || fdTable == NULL) { 835*11038SRao.Shoaib@Sun.COM evPrintf(ctx, 2, "pollfd() realloc (%ld) failed\n", 836*11038SRao.Shoaib@Sun.COM (long)maxnfds*sizeof(struct pollfd)); 837*11038SRao.Shoaib@Sun.COM return (-1); 8380Sstevel@tonic-gate } 839*11038SRao.Shoaib@Sun.COM 840*11038SRao.Shoaib@Sun.COM for (i = ctx->maxnfds; i < maxnfds; i++) { 8410Sstevel@tonic-gate ctx->pollfds[i].fd = -1; 8420Sstevel@tonic-gate ctx->pollfds[i].events = 0; 8430Sstevel@tonic-gate ctx->fdTable[i] = 0; 8440Sstevel@tonic-gate } 845*11038SRao.Shoaib@Sun.COM 846*11038SRao.Shoaib@Sun.COM ctx->maxnfds = maxnfds; 8470Sstevel@tonic-gate 848*11038SRao.Shoaib@Sun.COM return (0); 8490Sstevel@tonic-gate } 850*11038SRao.Shoaib@Sun.COM 8510Sstevel@tonic-gate /* Find the appropriate 'events' or 'revents' field in the pollfds array */ 8520Sstevel@tonic-gate short * 8530Sstevel@tonic-gate __fd_eventfield(int fd, __evEmulMask *maskp) { 854*11038SRao.Shoaib@Sun.COM 855*11038SRao.Shoaib@Sun.COM evContext_p *ctx = (evContext_p *)maskp->ctx; 856*11038SRao.Shoaib@Sun.COM 8570Sstevel@tonic-gate if (!maskp->result || maskp->type == EV_WASNONBLOCKING) 8580Sstevel@tonic-gate return (&(ctx->pollfds[fd].events)); 8590Sstevel@tonic-gate else 8600Sstevel@tonic-gate return (&(ctx->pollfds[fd].revents)); 8610Sstevel@tonic-gate } 862*11038SRao.Shoaib@Sun.COM 8630Sstevel@tonic-gate /* Translate to poll(2) event */ 8640Sstevel@tonic-gate short 8650Sstevel@tonic-gate __poll_event(__evEmulMask *maskp) { 866*11038SRao.Shoaib@Sun.COM 8670Sstevel@tonic-gate switch ((maskp)->type) { 8680Sstevel@tonic-gate case EV_READ: 8690Sstevel@tonic-gate return (POLLRDNORM); 8700Sstevel@tonic-gate case EV_WRITE: 8710Sstevel@tonic-gate return (POLLWRNORM); 8720Sstevel@tonic-gate case EV_EXCEPT: 8730Sstevel@tonic-gate return (POLLRDBAND | POLLPRI | POLLWRBAND); 8740Sstevel@tonic-gate case EV_WASNONBLOCKING: 8750Sstevel@tonic-gate return (POLLHUP); 8760Sstevel@tonic-gate default: 8770Sstevel@tonic-gate return (0); 8780Sstevel@tonic-gate } 8790Sstevel@tonic-gate } 880*11038SRao.Shoaib@Sun.COM 8810Sstevel@tonic-gate /* 8820Sstevel@tonic-gate * Clear the events corresponding to the specified mask. If this leaves 8830Sstevel@tonic-gate * the events mask empty (apart from the POLLHUP bit), set the fd field 8840Sstevel@tonic-gate * to -1 so that poll(2) will ignore this fd. 8850Sstevel@tonic-gate */ 8860Sstevel@tonic-gate void 8870Sstevel@tonic-gate __fd_clr(int fd, __evEmulMask *maskp) { 888*11038SRao.Shoaib@Sun.COM 889*11038SRao.Shoaib@Sun.COM evContext_p *ctx = maskp->ctx; 890*11038SRao.Shoaib@Sun.COM 8910Sstevel@tonic-gate *__fd_eventfield(fd, maskp) &= ~__poll_event(maskp); 8920Sstevel@tonic-gate if ((ctx->pollfds[fd].events & ~POLLHUP) == 0) { 8930Sstevel@tonic-gate ctx->pollfds[fd].fd = -1; 894*11038SRao.Shoaib@Sun.COM if (fd == ctx->fdMax) 895*11038SRao.Shoaib@Sun.COM while (ctx->fdMax > ctx->firstfd && 896*11038SRao.Shoaib@Sun.COM ctx->pollfds[ctx->fdMax].fd < 0) 897*11038SRao.Shoaib@Sun.COM ctx->fdMax--; 898*11038SRao.Shoaib@Sun.COM if (fd == ctx->firstfd) 899*11038SRao.Shoaib@Sun.COM while (ctx->firstfd <= ctx->fdMax && 900*11038SRao.Shoaib@Sun.COM ctx->pollfds[ctx->firstfd].fd < 0) 901*11038SRao.Shoaib@Sun.COM ctx->firstfd++; 902*11038SRao.Shoaib@Sun.COM /* 903*11038SRao.Shoaib@Sun.COM * Do we have a empty set of descriptors? 904*11038SRao.Shoaib@Sun.COM */ 905*11038SRao.Shoaib@Sun.COM if (ctx->firstfd > ctx->fdMax) { 906*11038SRao.Shoaib@Sun.COM ctx->fdMax = -1; 907*11038SRao.Shoaib@Sun.COM ctx->firstfd = 0; 908*11038SRao.Shoaib@Sun.COM } 9090Sstevel@tonic-gate } 9100Sstevel@tonic-gate } 911*11038SRao.Shoaib@Sun.COM 9120Sstevel@tonic-gate /* 9130Sstevel@tonic-gate * Set the events bit(s) corresponding to the specified mask. If the events 9140Sstevel@tonic-gate * field has any other bits than POLLHUP set, also set the fd field so that 9150Sstevel@tonic-gate * poll(2) will watch this fd. 9160Sstevel@tonic-gate */ 9170Sstevel@tonic-gate void 9180Sstevel@tonic-gate __fd_set(int fd, __evEmulMask *maskp) { 919*11038SRao.Shoaib@Sun.COM 920*11038SRao.Shoaib@Sun.COM evContext_p *ctx = maskp->ctx; 9210Sstevel@tonic-gate 9220Sstevel@tonic-gate *__fd_eventfield(fd, maskp) |= __poll_event(maskp); 9230Sstevel@tonic-gate if ((ctx->pollfds[fd].events & ~POLLHUP) != 0) { 9240Sstevel@tonic-gate ctx->pollfds[fd].fd = fd; 925*11038SRao.Shoaib@Sun.COM if (fd < ctx->firstfd || ctx->fdMax == -1) 9260Sstevel@tonic-gate ctx->firstfd = fd; 9270Sstevel@tonic-gate if (fd > ctx->fdMax) 9280Sstevel@tonic-gate ctx->fdMax = fd; 9290Sstevel@tonic-gate } 9300Sstevel@tonic-gate } 931*11038SRao.Shoaib@Sun.COM #endif /* USE_POLL */ 932*11038SRao.Shoaib@Sun.COM 933*11038SRao.Shoaib@Sun.COM /*! \file */ 934