xref: /onnv-gate/usr/src/lib/libresolv2/common/isc/eventlib.c (revision 11038:74b12212b8a2)
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
evCreate(evContext * opaqueCtx)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
evSetDebug(evContext opaqueCtx,int level,FILE * output)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
evDestroy(evContext opaqueCtx)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
evGetNext(evContext opaqueCtx,evEvent * opaqueEv,int options)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
evDispatch(evContext opaqueCtx,evEvent opaqueEv)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
evDrop(evContext opaqueCtx,evEvent opaqueEv)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
evMainLoop(evContext opaqueCtx)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
evHighestFD(evContext opaqueCtx)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
evPrintf(const evContext_p * ctx,int level,const char * fmt,...)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
evSetOption(evContext * opaqueCtx,const char * option,int value)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
evGetOption(evContext * opaqueCtx,const char * option,int * value)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
pselect(int nfds,void * rfds,void * wfds,void * efds,struct timespec * tsp,const sigset_t * sigmask)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
evPollfdRealloc(evContext_p * ctx,int pollfd_chunk_size,int fd)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 *
__fd_eventfield(int fd,__evEmulMask * maskp)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
__poll_event(__evEmulMask * maskp)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
__fd_clr(int fd,__evEmulMask * maskp)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
__fd_set(int fd,__evEmulMask * maskp)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