17c478bd9Sstevel@tonic-gate /*
29525b14bSRao 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  *
99525b14bSRao Shoaib  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
109525b14bSRao Shoaib  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
119525b14bSRao Shoaib  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
129525b14bSRao Shoaib  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
139525b14bSRao Shoaib  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
149525b14bSRao Shoaib  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
159525b14bSRao 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 #include "port_before.h"
237c478bd9Sstevel@tonic-gate #include "fd_setsize.h"
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include <sys/types.h>
267c478bd9Sstevel@tonic-gate #include <sys/time.h>
277c478bd9Sstevel@tonic-gate #include <sys/stat.h>
289525b14bSRao Shoaib #ifdef	SOLARIS2
297c478bd9Sstevel@tonic-gate #include <limits.h>
309525b14bSRao Shoaib #endif	/* SOLARIS2 */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <errno.h>
337c478bd9Sstevel@tonic-gate #include <signal.h>
347c478bd9Sstevel@tonic-gate #include <stdarg.h>
357c478bd9Sstevel@tonic-gate #include <stdlib.h>
367c478bd9Sstevel@tonic-gate #include <unistd.h>
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include <isc/eventlib.h>
397c478bd9Sstevel@tonic-gate #include <isc/assertions.h>
407c478bd9Sstevel@tonic-gate #include "eventlib_p.h"
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include "port_after.h"
437c478bd9Sstevel@tonic-gate 
449525b14bSRao Shoaib int      __evOptMonoTime;
459525b14bSRao Shoaib 
469525b14bSRao Shoaib #ifdef USE_POLL
479525b14bSRao Shoaib #define	pselect Pselect
489525b14bSRao Shoaib #endif /* USE_POLL */
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /* Forward. */
517c478bd9Sstevel@tonic-gate 
529525b14bSRao Shoaib #if defined(NEED_PSELECT) || defined(USE_POLL)
537c478bd9Sstevel@tonic-gate static int		pselect(int, void *, void *, void *,
547c478bd9Sstevel@tonic-gate 				struct timespec *,
557c478bd9Sstevel@tonic-gate 				const sigset_t *);
567c478bd9Sstevel@tonic-gate #endif
577c478bd9Sstevel@tonic-gate 
589525b14bSRao Shoaib int    __evOptMonoTime;
599525b14bSRao Shoaib 
607c478bd9Sstevel@tonic-gate /* Public. */
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate int
evCreate(evContext * opaqueCtx)637c478bd9Sstevel@tonic-gate evCreate(evContext *opaqueCtx) {
647c478bd9Sstevel@tonic-gate 	evContext_p *ctx;
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate 	/* Make sure the memory heap is initialized. */
677c478bd9Sstevel@tonic-gate 	if (meminit(0, 0) < 0 && errno != EEXIST)
687c478bd9Sstevel@tonic-gate 		return (-1);
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate 	OKNEW(ctx);
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	/* Global. */
737c478bd9Sstevel@tonic-gate 	ctx->cur = NULL;
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate 	/* Debugging. */
767c478bd9Sstevel@tonic-gate 	ctx->debug = 0;
777c478bd9Sstevel@tonic-gate 	ctx->output = NULL;
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 	/* Connections. */
807c478bd9Sstevel@tonic-gate 	ctx->conns = NULL;
817c478bd9Sstevel@tonic-gate 	INIT_LIST(ctx->accepts);
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 	/* Files. */
847c478bd9Sstevel@tonic-gate 	ctx->files = NULL;
859525b14bSRao Shoaib #ifdef USE_POLL
869525b14bSRao Shoaib         ctx->pollfds = NULL;
877c478bd9Sstevel@tonic-gate 	ctx->maxnfds = 0;
887c478bd9Sstevel@tonic-gate 	ctx->firstfd = 0;
897c478bd9Sstevel@tonic-gate 	emulMaskInit(ctx, rdLast, EV_READ, 1);
907c478bd9Sstevel@tonic-gate 	emulMaskInit(ctx, rdNext, EV_READ, 0);
917c478bd9Sstevel@tonic-gate 	emulMaskInit(ctx, wrLast, EV_WRITE, 1);
927c478bd9Sstevel@tonic-gate 	emulMaskInit(ctx, wrNext, EV_WRITE, 0);
937c478bd9Sstevel@tonic-gate 	emulMaskInit(ctx, exLast, EV_EXCEPT, 1);
947c478bd9Sstevel@tonic-gate 	emulMaskInit(ctx, exNext, EV_EXCEPT, 0);
957c478bd9Sstevel@tonic-gate 	emulMaskInit(ctx, nonblockBefore, EV_WASNONBLOCKING, 0);
969525b14bSRao Shoaib #endif /* USE_POLL */
977c478bd9Sstevel@tonic-gate 	FD_ZERO(&ctx->rdNext);
987c478bd9Sstevel@tonic-gate 	FD_ZERO(&ctx->wrNext);
997c478bd9Sstevel@tonic-gate 	FD_ZERO(&ctx->exNext);
1007c478bd9Sstevel@tonic-gate 	FD_ZERO(&ctx->nonblockBefore);
1017c478bd9Sstevel@tonic-gate 	ctx->fdMax = -1;
1027c478bd9Sstevel@tonic-gate 	ctx->fdNext = NULL;
1039525b14bSRao Shoaib 	ctx->fdCount = 0;	/*%< Invalidate {rd,wr,ex}Last. */
1049525b14bSRao Shoaib #ifndef USE_POLL
1057c478bd9Sstevel@tonic-gate 	ctx->highestFD = FD_SETSIZE - 1;
1069525b14bSRao Shoaib 	memset(ctx->fdTable, 0, sizeof ctx->fdTable);
107*55fea89dSDan Cross #else
1089525b14bSRao Shoaib 	ctx->highestFD = INT_MAX / sizeof(struct pollfd);
1099525b14bSRao Shoaib 	ctx->fdTable = NULL;
1109525b14bSRao Shoaib #endif /* USE_POLL */
1117c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
1127c478bd9Sstevel@tonic-gate 	ctx->lastFdCount = 0;
1137c478bd9Sstevel@tonic-gate #endif
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	/* Streams. */
1167c478bd9Sstevel@tonic-gate 	ctx->streams = NULL;
1177c478bd9Sstevel@tonic-gate 	ctx->strDone = NULL;
1187c478bd9Sstevel@tonic-gate 	ctx->strLast = NULL;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	/* Timers. */
1217c478bd9Sstevel@tonic-gate 	ctx->lastEventTime = evNowTime();
1227c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
1237c478bd9Sstevel@tonic-gate 	ctx->lastSelectTime = ctx->lastEventTime;
1247c478bd9Sstevel@tonic-gate #endif
1257c478bd9Sstevel@tonic-gate 	ctx->timers = evCreateTimers(ctx);
1267c478bd9Sstevel@tonic-gate 	if (ctx->timers == NULL)
1277c478bd9Sstevel@tonic-gate 		return (-1);
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	/* Waits. */
1307c478bd9Sstevel@tonic-gate 	ctx->waitLists = NULL;
1317c478bd9Sstevel@tonic-gate 	ctx->waitDone.first = ctx->waitDone.last = NULL;
1327c478bd9Sstevel@tonic-gate 	ctx->waitDone.prev = ctx->waitDone.next = NULL;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	opaqueCtx->opaque = ctx;
1357c478bd9Sstevel@tonic-gate 	return (0);
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate void
evSetDebug(evContext opaqueCtx,int level,FILE * output)1397c478bd9Sstevel@tonic-gate evSetDebug(evContext opaqueCtx, int level, FILE *output) {
1407c478bd9Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	ctx->debug = level;
1437c478bd9Sstevel@tonic-gate 	ctx->output = output;
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate int
evDestroy(evContext opaqueCtx)1477c478bd9Sstevel@tonic-gate evDestroy(evContext opaqueCtx) {
1487c478bd9Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
1499525b14bSRao Shoaib 	int revs = 424242;	/*%< Doug Adams. */
1507c478bd9Sstevel@tonic-gate 	evWaitList *this_wl, *next_wl;
1517c478bd9Sstevel@tonic-gate 	evWait *this_wait, *next_wait;
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	/* Connections. */
1547c478bd9Sstevel@tonic-gate 	while (revs-- > 0 && ctx->conns != NULL) {
1557c478bd9Sstevel@tonic-gate 		evConnID id;
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 		id.opaque = ctx->conns;
1587c478bd9Sstevel@tonic-gate 		(void) evCancelConn(opaqueCtx, id);
1597c478bd9Sstevel@tonic-gate 	}
1607c478bd9Sstevel@tonic-gate 	INSIST(revs >= 0);
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	/* Streams. */
1637c478bd9Sstevel@tonic-gate 	while (revs-- > 0 && ctx->streams != NULL) {
1647c478bd9Sstevel@tonic-gate 		evStreamID id;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 		id.opaque = ctx->streams;
1677c478bd9Sstevel@tonic-gate 		(void) evCancelRW(opaqueCtx, id);
1687c478bd9Sstevel@tonic-gate 	}
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	/* Files. */
1717c478bd9Sstevel@tonic-gate 	while (revs-- > 0 && ctx->files != NULL) {
1727c478bd9Sstevel@tonic-gate 		evFileID id;
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 		id.opaque = ctx->files;
1757c478bd9Sstevel@tonic-gate 		(void) evDeselectFD(opaqueCtx, id);
1767c478bd9Sstevel@tonic-gate 	}
1777c478bd9Sstevel@tonic-gate 	INSIST(revs >= 0);
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	/* Timers. */
1807c478bd9Sstevel@tonic-gate 	evDestroyTimers(ctx);
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	/* Waits. */
1837c478bd9Sstevel@tonic-gate 	for (this_wl = ctx->waitLists;
1847c478bd9Sstevel@tonic-gate 	     revs-- > 0 && this_wl != NULL;
1857c478bd9Sstevel@tonic-gate 	     this_wl = next_wl) {
1867c478bd9Sstevel@tonic-gate 		next_wl = this_wl->next;
1877c478bd9Sstevel@tonic-gate 		for (this_wait = this_wl->first;
1887c478bd9Sstevel@tonic-gate 		     revs-- > 0 && this_wait != NULL;
1897c478bd9Sstevel@tonic-gate 		     this_wait = next_wait) {
1907c478bd9Sstevel@tonic-gate 			next_wait = this_wait->next;
1917c478bd9Sstevel@tonic-gate 			FREE(this_wait);
1927c478bd9Sstevel@tonic-gate 		}
1937c478bd9Sstevel@tonic-gate 		FREE(this_wl);
1947c478bd9Sstevel@tonic-gate 	}
1957c478bd9Sstevel@tonic-gate 	for (this_wait = ctx->waitDone.first;
1967c478bd9Sstevel@tonic-gate 	     revs-- > 0 && this_wait != NULL;
1977c478bd9Sstevel@tonic-gate 	     this_wait = next_wait) {
1987c478bd9Sstevel@tonic-gate 		next_wait = this_wait->next;
1997c478bd9Sstevel@tonic-gate 		FREE(this_wait);
2007c478bd9Sstevel@tonic-gate 	}
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	FREE(ctx);
2037c478bd9Sstevel@tonic-gate 	return (0);
2047c478bd9Sstevel@tonic-gate }
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate int
evGetNext(evContext opaqueCtx,evEvent * opaqueEv,int options)2077c478bd9Sstevel@tonic-gate evGetNext(evContext opaqueCtx, evEvent *opaqueEv, int options) {
2087c478bd9Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
2097c478bd9Sstevel@tonic-gate 	struct timespec nextTime;
2107c478bd9Sstevel@tonic-gate 	evTimer *nextTimer;
2117c478bd9Sstevel@tonic-gate 	evEvent_p *new;
2127c478bd9Sstevel@tonic-gate 	int x, pselect_errno, timerPast;
2137c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
2147c478bd9Sstevel@tonic-gate 	struct timespec interval;
2157c478bd9Sstevel@tonic-gate #endif
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	/* Ensure that exactly one of EV_POLL or EV_WAIT was specified. */
2187c478bd9Sstevel@tonic-gate 	x = ((options & EV_POLL) != 0) + ((options & EV_WAIT) != 0);
2197c478bd9Sstevel@tonic-gate 	if (x != 1)
2207c478bd9Sstevel@tonic-gate 		EV_ERR(EINVAL);
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	/* Get the time of day.  We'll do this again after select() blocks. */
2237c478bd9Sstevel@tonic-gate 	ctx->lastEventTime = evNowTime();
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate  again:
2267c478bd9Sstevel@tonic-gate 	/* Finished accept()'s do not require a select(). */
2277c478bd9Sstevel@tonic-gate 	if (!EMPTY(ctx->accepts)) {
2287c478bd9Sstevel@tonic-gate 		OKNEW(new);
2297c478bd9Sstevel@tonic-gate 		new->type = Accept;
2307c478bd9Sstevel@tonic-gate 		new->u.accept.this = HEAD(ctx->accepts);
2317c478bd9Sstevel@tonic-gate 		UNLINK(ctx->accepts, HEAD(ctx->accepts), link);
2327c478bd9Sstevel@tonic-gate 		opaqueEv->opaque = new;
2337c478bd9Sstevel@tonic-gate 		return (0);
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	/* Stream IO does not require a select(). */
2377c478bd9Sstevel@tonic-gate 	if (ctx->strDone != NULL) {
2387c478bd9Sstevel@tonic-gate 		OKNEW(new);
2397c478bd9Sstevel@tonic-gate 		new->type = Stream;
2407c478bd9Sstevel@tonic-gate 		new->u.stream.this = ctx->strDone;
2417c478bd9Sstevel@tonic-gate 		ctx->strDone = ctx->strDone->nextDone;
2427c478bd9Sstevel@tonic-gate 		if (ctx->strDone == NULL)
2437c478bd9Sstevel@tonic-gate 			ctx->strLast = NULL;
2447c478bd9Sstevel@tonic-gate 		opaqueEv->opaque = new;
2457c478bd9Sstevel@tonic-gate 		return (0);
2467c478bd9Sstevel@tonic-gate 	}
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	/* Waits do not require a select(). */
2497c478bd9Sstevel@tonic-gate 	if (ctx->waitDone.first != NULL) {
2507c478bd9Sstevel@tonic-gate 		OKNEW(new);
2517c478bd9Sstevel@tonic-gate 		new->type = Wait;
2527c478bd9Sstevel@tonic-gate 		new->u.wait.this = ctx->waitDone.first;
2537c478bd9Sstevel@tonic-gate 		ctx->waitDone.first = ctx->waitDone.first->next;
2547c478bd9Sstevel@tonic-gate 		if (ctx->waitDone.first == NULL)
2557c478bd9Sstevel@tonic-gate 			ctx->waitDone.last = NULL;
2567c478bd9Sstevel@tonic-gate 		opaqueEv->opaque = new;
2577c478bd9Sstevel@tonic-gate 		return (0);
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	/* Get the status and content of the next timer. */
2617c478bd9Sstevel@tonic-gate 	if ((nextTimer = heap_element(ctx->timers, 1)) != NULL) {
2627c478bd9Sstevel@tonic-gate 		nextTime = nextTimer->due;
2637c478bd9Sstevel@tonic-gate 		timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
2647c478bd9Sstevel@tonic-gate 	} else
2659525b14bSRao Shoaib 		timerPast = 0;	/*%< Make gcc happy. */
2667c478bd9Sstevel@tonic-gate 	evPrintf(ctx, 9, "evGetNext: fdCount %d\n", ctx->fdCount);
2677c478bd9Sstevel@tonic-gate 	if (ctx->fdCount == 0) {
2687c478bd9Sstevel@tonic-gate 		static const struct timespec NoTime = {0, 0L};
2697c478bd9Sstevel@tonic-gate 		enum { JustPoll, Block, Timer } m;
2707c478bd9Sstevel@tonic-gate 		struct timespec t, *tp;
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 		/* Are there any events at all? */
2737c478bd9Sstevel@tonic-gate 		if ((options & EV_WAIT) != 0 && !nextTimer && ctx->fdMax == -1)
2747c478bd9Sstevel@tonic-gate 			EV_ERR(ENOENT);
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 		/* Figure out what select()'s timeout parameter should be. */
2777c478bd9Sstevel@tonic-gate 		if ((options & EV_POLL) != 0) {
2787c478bd9Sstevel@tonic-gate 			m = JustPoll;
2797c478bd9Sstevel@tonic-gate 			t = NoTime;
2807c478bd9Sstevel@tonic-gate 			tp = &t;
2817c478bd9Sstevel@tonic-gate 		} else if (nextTimer == NULL) {
2827c478bd9Sstevel@tonic-gate 			m = Block;
2837c478bd9Sstevel@tonic-gate 			/* ``t'' unused. */
2847c478bd9Sstevel@tonic-gate 			tp = NULL;
2857c478bd9Sstevel@tonic-gate 		} else if (timerPast) {
2867c478bd9Sstevel@tonic-gate 			m = JustPoll;
2877c478bd9Sstevel@tonic-gate 			t = NoTime;
2887c478bd9Sstevel@tonic-gate 			tp = &t;
2897c478bd9Sstevel@tonic-gate 		} else {
2907c478bd9Sstevel@tonic-gate 			m = Timer;
2917c478bd9Sstevel@tonic-gate 			/* ``t'' filled in later. */
2927c478bd9Sstevel@tonic-gate 			tp = &t;
2937c478bd9Sstevel@tonic-gate 		}
2947c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
2957c478bd9Sstevel@tonic-gate 		if (ctx->debug > 0) {
2967c478bd9Sstevel@tonic-gate 			interval = evSubTime(ctx->lastEventTime,
2977c478bd9Sstevel@tonic-gate 					     ctx->lastSelectTime);
2989525b14bSRao Shoaib 			if (interval.tv_sec > 0 || interval.tv_nsec > 0)
2997c478bd9Sstevel@tonic-gate 				evPrintf(ctx, 1,
3007c478bd9Sstevel@tonic-gate 				   "time between pselect() %u.%09u count %d\n",
3017c478bd9Sstevel@tonic-gate 					 interval.tv_sec, interval.tv_nsec,
3027c478bd9Sstevel@tonic-gate 					 ctx->lastFdCount);
3037c478bd9Sstevel@tonic-gate 		}
3047c478bd9Sstevel@tonic-gate #endif
3057c478bd9Sstevel@tonic-gate 		do {
3069525b14bSRao Shoaib #ifndef USE_POLL
3079525b14bSRao Shoaib 			 /* XXX need to copy only the bits we are using. */
3089525b14bSRao Shoaib 			 ctx->rdLast = ctx->rdNext;
3099525b14bSRao Shoaib 			 ctx->wrLast = ctx->wrNext;
3109525b14bSRao Shoaib 			 ctx->exLast = ctx->exNext;
3119525b14bSRao Shoaib #else
3127c478bd9Sstevel@tonic-gate 			/*
3137c478bd9Sstevel@tonic-gate 			 * The pollfd structure uses separate fields for
3147c478bd9Sstevel@tonic-gate 			 * the input and output events (corresponding to
3157c478bd9Sstevel@tonic-gate 			 * the ??Next and ??Last fd sets), so there's no
3167c478bd9Sstevel@tonic-gate 			 * need to copy one to the other.
3177c478bd9Sstevel@tonic-gate 			 */
3189525b14bSRao Shoaib #endif /* USE_POLL */
3197c478bd9Sstevel@tonic-gate 			if (m == Timer) {
3207c478bd9Sstevel@tonic-gate 				INSIST(tp == &t);
3217c478bd9Sstevel@tonic-gate 				t = evSubTime(nextTime, ctx->lastEventTime);
3227c478bd9Sstevel@tonic-gate 			}
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 			/* XXX should predict system's earliness and adjust. */
3257c478bd9Sstevel@tonic-gate 			x = pselect(ctx->fdMax+1,
3267c478bd9Sstevel@tonic-gate 				    &ctx->rdLast, &ctx->wrLast, &ctx->exLast,
3277c478bd9Sstevel@tonic-gate 				    tp, NULL);
3287c478bd9Sstevel@tonic-gate 			pselect_errno = errno;
3297c478bd9Sstevel@tonic-gate 
3309525b14bSRao Shoaib #ifndef USE_POLL
3317c478bd9Sstevel@tonic-gate 			evPrintf(ctx, 4, "select() returns %d (err: %s)\n",
3327c478bd9Sstevel@tonic-gate 				 x, (x == -1) ? strerror(errno) : "none");
3339525b14bSRao Shoaib #else
3349525b14bSRao Shoaib 			evPrintf(ctx, 4, "poll() returns %d (err: %s)\n",
3359525b14bSRao Shoaib 				x, (x == -1) ? strerror(errno) : "none");
3369525b14bSRao Shoaib #endif /* USE_POLL */
3377c478bd9Sstevel@tonic-gate 			/* Anything but a poll can change the time. */
3387c478bd9Sstevel@tonic-gate 			if (m != JustPoll)
3397c478bd9Sstevel@tonic-gate 				ctx->lastEventTime = evNowTime();
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 			/* Select() likes to finish about 10ms early. */
3427c478bd9Sstevel@tonic-gate 		} while (x == 0 && m == Timer &&
3437c478bd9Sstevel@tonic-gate 			 evCmpTime(ctx->lastEventTime, nextTime) < 0);
3447c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
3457c478bd9Sstevel@tonic-gate 		ctx->lastSelectTime = ctx->lastEventTime;
3467c478bd9Sstevel@tonic-gate #endif
3477c478bd9Sstevel@tonic-gate 		if (x < 0) {
3487c478bd9Sstevel@tonic-gate 			if (pselect_errno == EINTR) {
3497c478bd9Sstevel@tonic-gate 				if ((options & EV_NULL) != 0)
3507c478bd9Sstevel@tonic-gate 					goto again;
3517c478bd9Sstevel@tonic-gate 				OKNEW(new);
3527c478bd9Sstevel@tonic-gate 				new->type = Null;
3537c478bd9Sstevel@tonic-gate 				/* No data. */
3547c478bd9Sstevel@tonic-gate 				opaqueEv->opaque = new;
3557c478bd9Sstevel@tonic-gate 				return (0);
3567c478bd9Sstevel@tonic-gate 			}
3577c478bd9Sstevel@tonic-gate 			if (pselect_errno == EBADF) {
3587c478bd9Sstevel@tonic-gate 				for (x = 0; x <= ctx->fdMax; x++) {
3597c478bd9Sstevel@tonic-gate 					struct stat sb;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 					if (FD_ISSET(x, &ctx->rdNext) == 0 &&
3627c478bd9Sstevel@tonic-gate 					    FD_ISSET(x, &ctx->wrNext) == 0 &&
3637c478bd9Sstevel@tonic-gate 					    FD_ISSET(x, &ctx->exNext) == 0)
3647c478bd9Sstevel@tonic-gate 						continue;
3657c478bd9Sstevel@tonic-gate 					if (fstat(x, &sb) == -1 &&
3667c478bd9Sstevel@tonic-gate 					    errno == EBADF)
3677c478bd9Sstevel@tonic-gate 						evPrintf(ctx, 1, "EBADF: %d\n",
3687c478bd9Sstevel@tonic-gate 							 x);
3697c478bd9Sstevel@tonic-gate 				}
3707c478bd9Sstevel@tonic-gate 				abort();
3717c478bd9Sstevel@tonic-gate 			}
3727c478bd9Sstevel@tonic-gate 			EV_ERR(pselect_errno);
3737c478bd9Sstevel@tonic-gate 		}
3747c478bd9Sstevel@tonic-gate 		if (x == 0 && (nextTimer == NULL || !timerPast) &&
3757c478bd9Sstevel@tonic-gate 		    (options & EV_POLL))
3767c478bd9Sstevel@tonic-gate 			EV_ERR(EWOULDBLOCK);
3777c478bd9Sstevel@tonic-gate 		ctx->fdCount = x;
3787c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
3797c478bd9Sstevel@tonic-gate 		ctx->lastFdCount = x;
3807c478bd9Sstevel@tonic-gate #endif
3817c478bd9Sstevel@tonic-gate 	}
3827c478bd9Sstevel@tonic-gate 	INSIST(nextTimer || ctx->fdCount);
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	/* Timers go first since we'd like them to be accurate. */
3857c478bd9Sstevel@tonic-gate 	if (nextTimer && !timerPast) {
3867c478bd9Sstevel@tonic-gate 		/* Has anything happened since we blocked? */
3877c478bd9Sstevel@tonic-gate 		timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate 	if (nextTimer && timerPast) {
3907c478bd9Sstevel@tonic-gate 		OKNEW(new);
3917c478bd9Sstevel@tonic-gate 		new->type = Timer;
3927c478bd9Sstevel@tonic-gate 		new->u.timer.this = nextTimer;
3937c478bd9Sstevel@tonic-gate 		opaqueEv->opaque = new;
3947c478bd9Sstevel@tonic-gate 		return (0);
3957c478bd9Sstevel@tonic-gate 	}
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	/* No timers, so there should be a ready file descriptor. */
3987c478bd9Sstevel@tonic-gate 	x = 0;
3997c478bd9Sstevel@tonic-gate 	while (ctx->fdCount > 0) {
4007c478bd9Sstevel@tonic-gate 		evFile *fid;
4017c478bd9Sstevel@tonic-gate 		int fd, eventmask;
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 		if (ctx->fdNext == NULL) {
4047c478bd9Sstevel@tonic-gate 			if (++x == 2) {
4057c478bd9Sstevel@tonic-gate 				/*
4067c478bd9Sstevel@tonic-gate 				 * Hitting the end twice means that the last
4077c478bd9Sstevel@tonic-gate 				 * select() found some FD's which have since
4087c478bd9Sstevel@tonic-gate 				 * been deselected.
4097c478bd9Sstevel@tonic-gate 				 *
4107c478bd9Sstevel@tonic-gate 				 * On some systems, the count returned by
4117c478bd9Sstevel@tonic-gate 				 * selects is the total number of bits in
4127c478bd9Sstevel@tonic-gate 				 * all masks that are set, and on others it's
4137c478bd9Sstevel@tonic-gate 				 * the number of fd's that have some bit set,
414*55fea89dSDan Cross 				 * and on others, it's just broken.  We
4157c478bd9Sstevel@tonic-gate 				 * always assume that it's the number of
4167c478bd9Sstevel@tonic-gate 				 * bits set in all masks, because that's what
4177c478bd9Sstevel@tonic-gate 				 * the man page says it should do, and
4187c478bd9Sstevel@tonic-gate 				 * the worst that can happen is we do an
4197c478bd9Sstevel@tonic-gate 				 * extra select().
4207c478bd9Sstevel@tonic-gate 				 */
4217c478bd9Sstevel@tonic-gate 				ctx->fdCount = 0;
4227c478bd9Sstevel@tonic-gate 				break;
4237c478bd9Sstevel@tonic-gate 			}
4247c478bd9Sstevel@tonic-gate 			ctx->fdNext = ctx->files;
4257c478bd9Sstevel@tonic-gate 		}
4267c478bd9Sstevel@tonic-gate 		fid = ctx->fdNext;
4277c478bd9Sstevel@tonic-gate 		ctx->fdNext = fid->next;
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 		fd = fid->fd;
4307c478bd9Sstevel@tonic-gate 		eventmask = 0;
4317c478bd9Sstevel@tonic-gate 		if (FD_ISSET(fd, &ctx->rdLast))
4327c478bd9Sstevel@tonic-gate 			eventmask |= EV_READ;
4337c478bd9Sstevel@tonic-gate 		if (FD_ISSET(fd, &ctx->wrLast))
4347c478bd9Sstevel@tonic-gate 			eventmask |= EV_WRITE;
4357c478bd9Sstevel@tonic-gate 		if (FD_ISSET(fd, &ctx->exLast))
4367c478bd9Sstevel@tonic-gate 			eventmask |= EV_EXCEPT;
4377c478bd9Sstevel@tonic-gate 		eventmask &= fid->eventmask;
4387c478bd9Sstevel@tonic-gate 		if (eventmask != 0) {
4397c478bd9Sstevel@tonic-gate 			if ((eventmask & EV_READ) != 0) {
4407c478bd9Sstevel@tonic-gate 				FD_CLR(fd, &ctx->rdLast);
4417c478bd9Sstevel@tonic-gate 				ctx->fdCount--;
4427c478bd9Sstevel@tonic-gate 			}
4437c478bd9Sstevel@tonic-gate 			if ((eventmask & EV_WRITE) != 0) {
4447c478bd9Sstevel@tonic-gate 				FD_CLR(fd, &ctx->wrLast);
4457c478bd9Sstevel@tonic-gate 				ctx->fdCount--;
4467c478bd9Sstevel@tonic-gate 			}
4477c478bd9Sstevel@tonic-gate 			if ((eventmask & EV_EXCEPT) != 0) {
4487c478bd9Sstevel@tonic-gate 				FD_CLR(fd, &ctx->exLast);
4497c478bd9Sstevel@tonic-gate 				ctx->fdCount--;
4507c478bd9Sstevel@tonic-gate 			}
4517c478bd9Sstevel@tonic-gate 			OKNEW(new);
4527c478bd9Sstevel@tonic-gate 			new->type = File;
4537c478bd9Sstevel@tonic-gate 			new->u.file.this = fid;
4547c478bd9Sstevel@tonic-gate 			new->u.file.eventmask = eventmask;
4557c478bd9Sstevel@tonic-gate 			opaqueEv->opaque = new;
4567c478bd9Sstevel@tonic-gate 			return (0);
4577c478bd9Sstevel@tonic-gate 		}
4587c478bd9Sstevel@tonic-gate 	}
4597c478bd9Sstevel@tonic-gate 	if (ctx->fdCount < 0) {
4607c478bd9Sstevel@tonic-gate 		/*
4617c478bd9Sstevel@tonic-gate 		 * select()'s count is off on a number of systems, and
4627c478bd9Sstevel@tonic-gate 		 * can result in fdCount < 0.
4637c478bd9Sstevel@tonic-gate 		 */
4647c478bd9Sstevel@tonic-gate 		evPrintf(ctx, 4, "fdCount < 0 (%d)\n", ctx->fdCount);
4657c478bd9Sstevel@tonic-gate 		ctx->fdCount = 0;
4667c478bd9Sstevel@tonic-gate 	}
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	/* We get here if the caller deselect()'s an FD. Gag me with a goto. */
4697c478bd9Sstevel@tonic-gate 	goto again;
4707c478bd9Sstevel@tonic-gate }
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate int
evDispatch(evContext opaqueCtx,evEvent opaqueEv)4737c478bd9Sstevel@tonic-gate evDispatch(evContext opaqueCtx, evEvent opaqueEv) {
4747c478bd9Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
4757c478bd9Sstevel@tonic-gate 	evEvent_p *ev = opaqueEv.opaque;
4767c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
4777c478bd9Sstevel@tonic-gate 	void *func;
4787c478bd9Sstevel@tonic-gate 	struct timespec start_time;
4797c478bd9Sstevel@tonic-gate 	struct timespec interval;
4807c478bd9Sstevel@tonic-gate #endif
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
4837c478bd9Sstevel@tonic-gate 	if (ctx->debug > 0)
4847c478bd9Sstevel@tonic-gate 		start_time = evNowTime();
4857c478bd9Sstevel@tonic-gate #endif
4867c478bd9Sstevel@tonic-gate 	ctx->cur = ev;
4877c478bd9Sstevel@tonic-gate 	switch (ev->type) {
4887c478bd9Sstevel@tonic-gate 	    case Accept: {
4897c478bd9Sstevel@tonic-gate 		evAccept *this = ev->u.accept.this;
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 		evPrintf(ctx, 5,
4927c478bd9Sstevel@tonic-gate 			"Dispatch.Accept: fd %d -> %d, func %p, uap %p\n",
4937c478bd9Sstevel@tonic-gate 			 this->conn->fd, this->fd,
4947c478bd9Sstevel@tonic-gate 			 this->conn->func, this->conn->uap);
4957c478bd9Sstevel@tonic-gate 		errno = this->ioErrno;
4967c478bd9Sstevel@tonic-gate 		(this->conn->func)(opaqueCtx, this->conn->uap, this->fd,
4977c478bd9Sstevel@tonic-gate 				   &this->la, this->lalen,
4987c478bd9Sstevel@tonic-gate 				   &this->ra, this->ralen);
4997c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
5007c478bd9Sstevel@tonic-gate 		func = this->conn->func;
5017c478bd9Sstevel@tonic-gate #endif
5027c478bd9Sstevel@tonic-gate 		break;
5037c478bd9Sstevel@tonic-gate 	    }
5047c478bd9Sstevel@tonic-gate 	    case File: {
5057c478bd9Sstevel@tonic-gate 		evFile *this = ev->u.file.this;
5067c478bd9Sstevel@tonic-gate 		int eventmask = ev->u.file.eventmask;
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 		evPrintf(ctx, 5,
5097c478bd9Sstevel@tonic-gate 			"Dispatch.File: fd %d, mask 0x%x, func %p, uap %p\n",
5107c478bd9Sstevel@tonic-gate 			 this->fd, this->eventmask, this->func, this->uap);
5117c478bd9Sstevel@tonic-gate 		(this->func)(opaqueCtx, this->uap, this->fd, eventmask);
5127c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
5137c478bd9Sstevel@tonic-gate 		func = this->func;
5147c478bd9Sstevel@tonic-gate #endif
5157c478bd9Sstevel@tonic-gate 		break;
5167c478bd9Sstevel@tonic-gate 	    }
5177c478bd9Sstevel@tonic-gate 	    case Stream: {
5187c478bd9Sstevel@tonic-gate 		evStream *this = ev->u.stream.this;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 		evPrintf(ctx, 5,
5217c478bd9Sstevel@tonic-gate 			 "Dispatch.Stream: fd %d, func %p, uap %p\n",
5227c478bd9Sstevel@tonic-gate 			 this->fd, this->func, this->uap);
5237c478bd9Sstevel@tonic-gate 		errno = this->ioErrno;
5247c478bd9Sstevel@tonic-gate 		(this->func)(opaqueCtx, this->uap, this->fd, this->ioDone);
5257c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
5267c478bd9Sstevel@tonic-gate 		func = this->func;
5277c478bd9Sstevel@tonic-gate #endif
5287c478bd9Sstevel@tonic-gate 		break;
5297c478bd9Sstevel@tonic-gate 	    }
5307c478bd9Sstevel@tonic-gate 	    case Timer: {
5317c478bd9Sstevel@tonic-gate 		evTimer *this = ev->u.timer.this;
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 		evPrintf(ctx, 5, "Dispatch.Timer: func %p, uap %p\n",
5347c478bd9Sstevel@tonic-gate 			 this->func, this->uap);
5357c478bd9Sstevel@tonic-gate 		(this->func)(opaqueCtx, this->uap, this->due, this->inter);
5367c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
5377c478bd9Sstevel@tonic-gate 		func = this->func;
5387c478bd9Sstevel@tonic-gate #endif
5397c478bd9Sstevel@tonic-gate 		break;
5407c478bd9Sstevel@tonic-gate 	    }
5417c478bd9Sstevel@tonic-gate 	    case Wait: {
5427c478bd9Sstevel@tonic-gate 		evWait *this = ev->u.wait.this;
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 		evPrintf(ctx, 5,
5457c478bd9Sstevel@tonic-gate 			 "Dispatch.Wait: tag %p, func %p, uap %p\n",
5467c478bd9Sstevel@tonic-gate 			 this->tag, this->func, this->uap);
5477c478bd9Sstevel@tonic-gate 		(this->func)(opaqueCtx, this->uap, this->tag);
5487c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
5497c478bd9Sstevel@tonic-gate 		func = this->func;
5507c478bd9Sstevel@tonic-gate #endif
5517c478bd9Sstevel@tonic-gate 		break;
5527c478bd9Sstevel@tonic-gate 	    }
5537c478bd9Sstevel@tonic-gate 	    case Null: {
5547c478bd9Sstevel@tonic-gate 		/* No work. */
5557c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
5567c478bd9Sstevel@tonic-gate 		func = NULL;
5577c478bd9Sstevel@tonic-gate #endif
5587c478bd9Sstevel@tonic-gate 		break;
5597c478bd9Sstevel@tonic-gate 	    }
5607c478bd9Sstevel@tonic-gate 	    default: {
5617c478bd9Sstevel@tonic-gate 		abort();
5627c478bd9Sstevel@tonic-gate 	    }
5637c478bd9Sstevel@tonic-gate 	}
5647c478bd9Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
5657c478bd9Sstevel@tonic-gate 	if (ctx->debug > 0) {
5667c478bd9Sstevel@tonic-gate 		interval = evSubTime(evNowTime(), start_time);
567*55fea89dSDan Cross 		/*
5687c478bd9Sstevel@tonic-gate 		 * Complain if it took longer than 50 milliseconds.
5697c478bd9Sstevel@tonic-gate 		 *
5707c478bd9Sstevel@tonic-gate 		 * We call getuid() to make an easy to find mark in a kernel
5717c478bd9Sstevel@tonic-gate 		 * trace.
5727c478bd9Sstevel@tonic-gate 		 */
5737c478bd9Sstevel@tonic-gate 		if (interval.tv_sec > 0 || interval.tv_nsec > 50000000)
5747c478bd9Sstevel@tonic-gate 			evPrintf(ctx, 1,
5757c478bd9Sstevel@tonic-gate 			 "dispatch interval %u.%09u uid %d type %d func %p\n",
5767c478bd9Sstevel@tonic-gate 				 interval.tv_sec, interval.tv_nsec,
5777c478bd9Sstevel@tonic-gate 				 getuid(), ev->type, func);
5787c478bd9Sstevel@tonic-gate 	}
5797c478bd9Sstevel@tonic-gate #endif
5807c478bd9Sstevel@tonic-gate 	ctx->cur = NULL;
5817c478bd9Sstevel@tonic-gate 	evDrop(opaqueCtx, opaqueEv);
5827c478bd9Sstevel@tonic-gate 	return (0);
5837c478bd9Sstevel@tonic-gate }
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate void
evDrop(evContext opaqueCtx,evEvent opaqueEv)5867c478bd9Sstevel@tonic-gate evDrop(evContext opaqueCtx, evEvent opaqueEv) {
5877c478bd9Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
5887c478bd9Sstevel@tonic-gate 	evEvent_p *ev = opaqueEv.opaque;
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	switch (ev->type) {
5917c478bd9Sstevel@tonic-gate 	    case Accept: {
5927c478bd9Sstevel@tonic-gate 		FREE(ev->u.accept.this);
5937c478bd9Sstevel@tonic-gate 		break;
5947c478bd9Sstevel@tonic-gate 	    }
5957c478bd9Sstevel@tonic-gate 	    case File: {
5967c478bd9Sstevel@tonic-gate 		/* No work. */
5977c478bd9Sstevel@tonic-gate 		break;
5987c478bd9Sstevel@tonic-gate 	    }
5997c478bd9Sstevel@tonic-gate 	    case Stream: {
6007c478bd9Sstevel@tonic-gate 		evStreamID id;
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 		id.opaque = ev->u.stream.this;
6037c478bd9Sstevel@tonic-gate 		(void) evCancelRW(opaqueCtx, id);
6047c478bd9Sstevel@tonic-gate 		break;
6057c478bd9Sstevel@tonic-gate 	    }
6067c478bd9Sstevel@tonic-gate 	    case Timer: {
6077c478bd9Sstevel@tonic-gate 		evTimer *this = ev->u.timer.this;
6087c478bd9Sstevel@tonic-gate 		evTimerID opaque;
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 		/* Check to see whether the user func cleared the timer. */
6117c478bd9Sstevel@tonic-gate 		if (heap_element(ctx->timers, this->index) != this) {
6127c478bd9Sstevel@tonic-gate 			evPrintf(ctx, 5, "Dispatch.Timer: timer rm'd?\n");
6137c478bd9Sstevel@tonic-gate 			break;
6147c478bd9Sstevel@tonic-gate 		}
6157c478bd9Sstevel@tonic-gate 		/*
6167c478bd9Sstevel@tonic-gate 		 * Timer is still there.  Delete it if it has expired,
6177c478bd9Sstevel@tonic-gate 		 * otherwise set it according to its next interval.
6187c478bd9Sstevel@tonic-gate 		 */
6199525b14bSRao Shoaib 		if (this->inter.tv_sec == (time_t)0 &&
6209525b14bSRao Shoaib 		    this->inter.tv_nsec == 0L) {
621*55fea89dSDan Cross 			opaque.opaque = this;
6227c478bd9Sstevel@tonic-gate 			(void) evClearTimer(opaqueCtx, opaque);
6237c478bd9Sstevel@tonic-gate 		} else {
6247c478bd9Sstevel@tonic-gate 			opaque.opaque = this;
6257c478bd9Sstevel@tonic-gate 			(void) evResetTimer(opaqueCtx, opaque, this->func,
6267c478bd9Sstevel@tonic-gate 					    this->uap,
6279525b14bSRao Shoaib 					    evAddTime((this->mode & EV_TMR_RATE) ?
6289525b14bSRao Shoaib 						      this->due :
6299525b14bSRao Shoaib 						      ctx->lastEventTime,
6307c478bd9Sstevel@tonic-gate 						      this->inter),
6317c478bd9Sstevel@tonic-gate 					    this->inter);
6327c478bd9Sstevel@tonic-gate 		}
6337c478bd9Sstevel@tonic-gate 		break;
6347c478bd9Sstevel@tonic-gate 	    }
6357c478bd9Sstevel@tonic-gate 	    case Wait: {
6367c478bd9Sstevel@tonic-gate 		FREE(ev->u.wait.this);
6377c478bd9Sstevel@tonic-gate 		break;
6387c478bd9Sstevel@tonic-gate 	    }
6397c478bd9Sstevel@tonic-gate 	    case Null: {
6407c478bd9Sstevel@tonic-gate 		/* No work. */
6417c478bd9Sstevel@tonic-gate 		break;
6427c478bd9Sstevel@tonic-gate 	    }
6437c478bd9Sstevel@tonic-gate 	    default: {
6447c478bd9Sstevel@tonic-gate 		abort();
6457c478bd9Sstevel@tonic-gate 	    }
6467c478bd9Sstevel@tonic-gate 	}
6477c478bd9Sstevel@tonic-gate 	FREE(ev);
6487c478bd9Sstevel@tonic-gate }
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate int
evMainLoop(evContext opaqueCtx)6517c478bd9Sstevel@tonic-gate evMainLoop(evContext opaqueCtx) {
6527c478bd9Sstevel@tonic-gate 	evEvent event;
6537c478bd9Sstevel@tonic-gate 	int x;
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0)
6567c478bd9Sstevel@tonic-gate 		if ((x = evDispatch(opaqueCtx, event)) < 0)
6577c478bd9Sstevel@tonic-gate 			break;
6587c478bd9Sstevel@tonic-gate 	return (x);
6597c478bd9Sstevel@tonic-gate }
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate int
evHighestFD(evContext opaqueCtx)6627c478bd9Sstevel@tonic-gate evHighestFD(evContext opaqueCtx) {
6637c478bd9Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	return (ctx->highestFD);
6667c478bd9Sstevel@tonic-gate }
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate void
evPrintf(const evContext_p * ctx,int level,const char * fmt,...)6697c478bd9Sstevel@tonic-gate evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) {
6707c478bd9Sstevel@tonic-gate 	va_list ap;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
6737c478bd9Sstevel@tonic-gate 	if (ctx->output != NULL && ctx->debug >= level) {
6747c478bd9Sstevel@tonic-gate 		vfprintf(ctx->output, fmt, ap);
6757c478bd9Sstevel@tonic-gate 		fflush(ctx->output);
6767c478bd9Sstevel@tonic-gate 	}
6777c478bd9Sstevel@tonic-gate 	va_end(ap);
6787c478bd9Sstevel@tonic-gate }
6797c478bd9Sstevel@tonic-gate 
6809525b14bSRao Shoaib int
evSetOption(evContext * opaqueCtx,const char * option,int value)6819525b14bSRao Shoaib evSetOption(evContext *opaqueCtx, const char *option, int value) {
6829525b14bSRao Shoaib 	/* evContext_p *ctx = opaqueCtx->opaque; */
6839525b14bSRao Shoaib 
6849525b14bSRao Shoaib 	UNUSED(opaqueCtx);
6859525b14bSRao Shoaib 	UNUSED(value);
6869525b14bSRao Shoaib #ifndef CLOCK_MONOTONIC
6879525b14bSRao Shoaib 	UNUSED(option);
688*55fea89dSDan Cross #endif
6899525b14bSRao Shoaib 
6909525b14bSRao Shoaib #ifdef CLOCK_MONOTONIC
6919525b14bSRao Shoaib 	if (strcmp(option, "monotime") == 0) {
6929525b14bSRao Shoaib 		if (opaqueCtx  != NULL)
6939525b14bSRao Shoaib 			errno = EINVAL;
6949525b14bSRao Shoaib 		if (value == 0 || value == 1) {
6959525b14bSRao Shoaib 			__evOptMonoTime = value;
6969525b14bSRao Shoaib 			return (0);
6979525b14bSRao Shoaib 		} else {
6989525b14bSRao Shoaib 			errno = EINVAL;
6999525b14bSRao Shoaib 			return (-1);
7009525b14bSRao Shoaib 		}
701*55fea89dSDan Cross 	}
7029525b14bSRao Shoaib #endif
7039525b14bSRao Shoaib 	errno = ENOENT;
7049525b14bSRao Shoaib 	return (-1);
7059525b14bSRao Shoaib }
7069525b14bSRao Shoaib 
7079525b14bSRao Shoaib int
evGetOption(evContext * opaqueCtx,const char * option,int * value)7089525b14bSRao Shoaib evGetOption(evContext *opaqueCtx, const char *option, int *value) {
7099525b14bSRao Shoaib 	/* evContext_p *ctx = opaqueCtx->opaque; */
7109525b14bSRao Shoaib 
7119525b14bSRao Shoaib 	UNUSED(opaqueCtx);
7129525b14bSRao Shoaib #ifndef CLOCK_MONOTONIC
7139525b14bSRao Shoaib 	UNUSED(value);
7149525b14bSRao Shoaib 	UNUSED(option);
715*55fea89dSDan Cross #endif
7169525b14bSRao Shoaib 
7179525b14bSRao Shoaib #ifdef CLOCK_MONOTONIC
7189525b14bSRao Shoaib 	if (strcmp(option, "monotime") == 0) {
7199525b14bSRao Shoaib 		if (opaqueCtx  != NULL)
7209525b14bSRao Shoaib 			errno = EINVAL;
7219525b14bSRao Shoaib 		*value = __evOptMonoTime;
7229525b14bSRao Shoaib 		return (0);
7239525b14bSRao Shoaib 	}
7249525b14bSRao Shoaib #endif
7259525b14bSRao Shoaib 	errno = ENOENT;
7269525b14bSRao Shoaib 	return (-1);
7279525b14bSRao Shoaib }
7289525b14bSRao Shoaib 
7299525b14bSRao Shoaib #if defined(NEED_PSELECT) || defined(USE_POLL)
7307c478bd9Sstevel@tonic-gate /* XXX needs to move to the porting library. */
7317c478bd9Sstevel@tonic-gate static int
pselect(int nfds,void * rfds,void * wfds,void * efds,struct timespec * tsp,const sigset_t * sigmask)7327c478bd9Sstevel@tonic-gate pselect(int nfds, void *rfds, void *wfds, void *efds,
7337c478bd9Sstevel@tonic-gate 	struct timespec *tsp,
7347c478bd9Sstevel@tonic-gate 	const sigset_t *sigmask)
7357c478bd9Sstevel@tonic-gate {
7366e060960SToomas Soome 	struct timeval tv;
7377c478bd9Sstevel@tonic-gate 	sigset_t sigs;
7387c478bd9Sstevel@tonic-gate 	int n;
7399525b14bSRao Shoaib #ifdef USE_POLL
7409525b14bSRao Shoaib 	int	polltimeout = INFTIM;
7417c478bd9Sstevel@tonic-gate 	evContext_p	*ctx;
7427c478bd9Sstevel@tonic-gate 	struct pollfd	*fds;
7437c478bd9Sstevel@tonic-gate 	nfds_t		pnfds;
7449525b14bSRao Shoaib 
7459525b14bSRao Shoaib 	UNUSED(nfds);
7466e060960SToomas Soome #else
7476e060960SToomas Soome 	struct timeval *tvp = NULL;
7489525b14bSRao Shoaib #endif /* USE_POLL */
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	if (tsp) {
7517c478bd9Sstevel@tonic-gate 		tv = evTimeVal(*tsp);
7529525b14bSRao Shoaib #ifdef USE_POLL
7539525b14bSRao Shoaib 		polltimeout = 1000 * tv.tv_sec + tv.tv_usec / 1000;
7546e060960SToomas Soome #else
7556e060960SToomas Soome 		tvp = &tv;
7569525b14bSRao Shoaib #endif /* USE_POLL */
7576e060960SToomas Soome 	}
7587c478bd9Sstevel@tonic-gate 	if (sigmask)
7597c478bd9Sstevel@tonic-gate 		sigprocmask(SIG_SETMASK, sigmask, &sigs);
7609525b14bSRao Shoaib #ifndef USE_POLL
7619525b14bSRao Shoaib 	 n = select(nfds, rfds, wfds, efds, tvp);
7629525b14bSRao Shoaib #else
7639525b14bSRao Shoaib         /*
7647c478bd9Sstevel@tonic-gate 	 * rfds, wfds, and efds should all be from the same evContext_p,
7657c478bd9Sstevel@tonic-gate 	 * so any of them will do. If they're all NULL, the caller is
7667c478bd9Sstevel@tonic-gate 	 * presumably calling us to block.
7677c478bd9Sstevel@tonic-gate 	 */
7689525b14bSRao Shoaib 	if (rfds != NULL)
7697c478bd9Sstevel@tonic-gate 		ctx = ((__evEmulMask *)rfds)->ctx;
7709525b14bSRao Shoaib 	else if (wfds != NULL)
7717c478bd9Sstevel@tonic-gate 		ctx = ((__evEmulMask *)wfds)->ctx;
7729525b14bSRao Shoaib 	else if (efds != NULL)
7737c478bd9Sstevel@tonic-gate 		ctx = ((__evEmulMask *)efds)->ctx;
7747c478bd9Sstevel@tonic-gate 	else
7759525b14bSRao Shoaib 		ctx = NULL;
7769525b14bSRao Shoaib 	if (ctx != NULL && ctx->fdMax != -1) {
7777c478bd9Sstevel@tonic-gate 		fds = &(ctx->pollfds[ctx->firstfd]);
7787c478bd9Sstevel@tonic-gate 		pnfds = ctx->fdMax - ctx->firstfd + 1;
7797c478bd9Sstevel@tonic-gate 	} else {
7809525b14bSRao Shoaib 		fds = NULL;
7817c478bd9Sstevel@tonic-gate 		pnfds = 0;
7827c478bd9Sstevel@tonic-gate 	}
7837c478bd9Sstevel@tonic-gate 	n = poll(fds, pnfds, polltimeout);
7847c478bd9Sstevel@tonic-gate 	if (n > 0) {
7859525b14bSRao Shoaib 		int     i, e;
7869525b14bSRao Shoaib 
7879525b14bSRao Shoaib 		INSIST(ctx != NULL);
7887c478bd9Sstevel@tonic-gate 		for (e = 0, i = ctx->firstfd; i <= ctx->fdMax; i++) {
7897c478bd9Sstevel@tonic-gate 			if (ctx->pollfds[i].fd < 0)
7907c478bd9Sstevel@tonic-gate 				continue;
7917c478bd9Sstevel@tonic-gate 			if (FD_ISSET(i, &ctx->rdLast))
7927c478bd9Sstevel@tonic-gate 				e++;
7937c478bd9Sstevel@tonic-gate 			if (FD_ISSET(i, &ctx->wrLast))
7947c478bd9Sstevel@tonic-gate 				e++;
7957c478bd9Sstevel@tonic-gate 			if (FD_ISSET(i, &ctx->exLast))
7967c478bd9Sstevel@tonic-gate 				e++;
7977c478bd9Sstevel@tonic-gate 		}
7987c478bd9Sstevel@tonic-gate 		n = e;
7997c478bd9Sstevel@tonic-gate 	}
8009525b14bSRao Shoaib #endif /* USE_POLL */
8017c478bd9Sstevel@tonic-gate 	if (sigmask)
8027c478bd9Sstevel@tonic-gate 		sigprocmask(SIG_SETMASK, &sigs, NULL);
8037c478bd9Sstevel@tonic-gate 	if (tsp)
8047c478bd9Sstevel@tonic-gate 		*tsp = evTimeSpec(tv);
8057c478bd9Sstevel@tonic-gate 	return (n);
8067c478bd9Sstevel@tonic-gate }
8077c478bd9Sstevel@tonic-gate #endif
8087c478bd9Sstevel@tonic-gate 
8099525b14bSRao Shoaib #ifdef USE_POLL
8109525b14bSRao Shoaib int
evPollfdRealloc(evContext_p * ctx,int pollfd_chunk_size,int fd)8117c478bd9Sstevel@tonic-gate evPollfdRealloc(evContext_p *ctx, int pollfd_chunk_size, int fd) {
812*55fea89dSDan Cross 
8139525b14bSRao Shoaib 	int     i, maxnfds;
8149525b14bSRao Shoaib 	void	*pollfds, *fdTable;
815*55fea89dSDan Cross 
8169525b14bSRao Shoaib 	if (fd < ctx->maxnfds)
8179525b14bSRao Shoaib 		return (0);
818*55fea89dSDan Cross 
8197c478bd9Sstevel@tonic-gate 	/* Don't allow ridiculously small values for pollfd_chunk_size */
8207c478bd9Sstevel@tonic-gate 	if (pollfd_chunk_size < 20)
8217c478bd9Sstevel@tonic-gate 		pollfd_chunk_size = 20;
822*55fea89dSDan Cross 
8239525b14bSRao Shoaib 	maxnfds = (1 + (fd/pollfd_chunk_size)) * pollfd_chunk_size;
824*55fea89dSDan Cross 
8259525b14bSRao Shoaib 	pollfds = realloc(ctx->pollfds, maxnfds * sizeof(*ctx->pollfds));
8269525b14bSRao Shoaib 	if (pollfds != NULL)
8279525b14bSRao Shoaib 		ctx->pollfds = pollfds;
8289525b14bSRao Shoaib 	fdTable = realloc(ctx->fdTable, maxnfds * sizeof(*ctx->fdTable));
8299525b14bSRao Shoaib 	if (fdTable != NULL)
8309525b14bSRao Shoaib 		ctx->fdTable = fdTable;
831*55fea89dSDan Cross 
8329525b14bSRao Shoaib 	if (pollfds == NULL || fdTable == NULL) {
8339525b14bSRao Shoaib 		evPrintf(ctx, 2, "pollfd() realloc (%ld) failed\n",
8349525b14bSRao Shoaib 			 (long)maxnfds*sizeof(struct pollfd));
8359525b14bSRao Shoaib 		return (-1);
8367c478bd9Sstevel@tonic-gate 	}
837*55fea89dSDan Cross 
8389525b14bSRao Shoaib 	for (i = ctx->maxnfds; i < maxnfds; i++) {
8397c478bd9Sstevel@tonic-gate 		ctx->pollfds[i].fd = -1;
8407c478bd9Sstevel@tonic-gate 		ctx->pollfds[i].events = 0;
8417c478bd9Sstevel@tonic-gate 		ctx->fdTable[i] = 0;
8427c478bd9Sstevel@tonic-gate 	}
8437c478bd9Sstevel@tonic-gate 
8449525b14bSRao Shoaib 	ctx->maxnfds = maxnfds;
8457c478bd9Sstevel@tonic-gate 
8469525b14bSRao Shoaib 	return (0);
8477c478bd9Sstevel@tonic-gate }
848*55fea89dSDan Cross 
8497c478bd9Sstevel@tonic-gate /* Find the appropriate 'events' or 'revents' field in the pollfds array */
8507c478bd9Sstevel@tonic-gate short *
__fd_eventfield(int fd,__evEmulMask * maskp)8517c478bd9Sstevel@tonic-gate __fd_eventfield(int fd, __evEmulMask *maskp) {
852*55fea89dSDan Cross 
8539525b14bSRao Shoaib 	evContext_p     *ctx = (evContext_p *)maskp->ctx;
854*55fea89dSDan Cross 
8557c478bd9Sstevel@tonic-gate 	if (!maskp->result || maskp->type == EV_WASNONBLOCKING)
8567c478bd9Sstevel@tonic-gate 		return (&(ctx->pollfds[fd].events));
8577c478bd9Sstevel@tonic-gate 	else
8587c478bd9Sstevel@tonic-gate 		return (&(ctx->pollfds[fd].revents));
8597c478bd9Sstevel@tonic-gate }
860*55fea89dSDan Cross 
8617c478bd9Sstevel@tonic-gate /* Translate to poll(2) event */
8627c478bd9Sstevel@tonic-gate short
__poll_event(__evEmulMask * maskp)8637c478bd9Sstevel@tonic-gate __poll_event(__evEmulMask *maskp) {
864*55fea89dSDan Cross 
8657c478bd9Sstevel@tonic-gate 	switch ((maskp)->type) {
8667c478bd9Sstevel@tonic-gate 	case EV_READ:
8677c478bd9Sstevel@tonic-gate 		return (POLLRDNORM);
8687c478bd9Sstevel@tonic-gate 	case EV_WRITE:
8697c478bd9Sstevel@tonic-gate 		return (POLLWRNORM);
8707c478bd9Sstevel@tonic-gate 	case EV_EXCEPT:
8717c478bd9Sstevel@tonic-gate 		return (POLLRDBAND | POLLPRI | POLLWRBAND);
8727c478bd9Sstevel@tonic-gate 	case EV_WASNONBLOCKING:
8737c478bd9Sstevel@tonic-gate 		return (POLLHUP);
8747c478bd9Sstevel@tonic-gate 	default:
8757c478bd9Sstevel@tonic-gate 		return (0);
8767c478bd9Sstevel@tonic-gate 	}
8777c478bd9Sstevel@tonic-gate }
878*55fea89dSDan Cross 
8797c478bd9Sstevel@tonic-gate /*
8807c478bd9Sstevel@tonic-gate  * Clear the events corresponding to the specified mask. If this leaves
8817c478bd9Sstevel@tonic-gate  * the events mask empty (apart from the POLLHUP bit), set the fd field
8827c478bd9Sstevel@tonic-gate  * to -1 so that poll(2) will ignore this fd.
8837c478bd9Sstevel@tonic-gate  */
8847c478bd9Sstevel@tonic-gate void
__fd_clr(int fd,__evEmulMask * maskp)8857c478bd9Sstevel@tonic-gate __fd_clr(int fd, __evEmulMask *maskp) {
886*55fea89dSDan Cross 
8879525b14bSRao Shoaib 	evContext_p     *ctx = maskp->ctx;
888*55fea89dSDan Cross 
8897c478bd9Sstevel@tonic-gate 	*__fd_eventfield(fd, maskp) &= ~__poll_event(maskp);
8907c478bd9Sstevel@tonic-gate 	if ((ctx->pollfds[fd].events & ~POLLHUP) == 0) {
8917c478bd9Sstevel@tonic-gate 		ctx->pollfds[fd].fd = -1;
8929525b14bSRao Shoaib 		if (fd == ctx->fdMax)
8939525b14bSRao Shoaib 			while (ctx->fdMax > ctx->firstfd &&
8949525b14bSRao Shoaib 			       ctx->pollfds[ctx->fdMax].fd < 0)
8959525b14bSRao Shoaib 				ctx->fdMax--;
8969525b14bSRao Shoaib 		if (fd == ctx->firstfd)
8979525b14bSRao Shoaib 			while (ctx->firstfd <= ctx->fdMax &&
8989525b14bSRao Shoaib 			       ctx->pollfds[ctx->firstfd].fd < 0)
8999525b14bSRao Shoaib 				ctx->firstfd++;
9009525b14bSRao Shoaib 		/*
9019525b14bSRao Shoaib 		 * Do we have a empty set of descriptors?
9029525b14bSRao Shoaib 		 */
9039525b14bSRao Shoaib 		if (ctx->firstfd > ctx->fdMax) {
9049525b14bSRao Shoaib 			ctx->fdMax = -1;
9059525b14bSRao Shoaib 			ctx->firstfd = 0;
9069525b14bSRao Shoaib 		}
9077c478bd9Sstevel@tonic-gate 	}
9087c478bd9Sstevel@tonic-gate }
909*55fea89dSDan Cross 
9107c478bd9Sstevel@tonic-gate /*
9117c478bd9Sstevel@tonic-gate  * Set the events bit(s) corresponding to the specified mask. If the events
9127c478bd9Sstevel@tonic-gate  * field has any other bits than POLLHUP set, also set the fd field so that
9137c478bd9Sstevel@tonic-gate  * poll(2) will watch this fd.
9147c478bd9Sstevel@tonic-gate  */
9157c478bd9Sstevel@tonic-gate void
__fd_set(int fd,__evEmulMask * maskp)9167c478bd9Sstevel@tonic-gate __fd_set(int fd, __evEmulMask *maskp) {
917*55fea89dSDan Cross 
9189525b14bSRao Shoaib 	evContext_p     *ctx = maskp->ctx;
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	*__fd_eventfield(fd, maskp) |= __poll_event(maskp);
9217c478bd9Sstevel@tonic-gate 	if ((ctx->pollfds[fd].events & ~POLLHUP) != 0) {
9227c478bd9Sstevel@tonic-gate 		ctx->pollfds[fd].fd = fd;
9239525b14bSRao Shoaib 		if (fd < ctx->firstfd || ctx->fdMax == -1)
9247c478bd9Sstevel@tonic-gate 			ctx->firstfd = fd;
9257c478bd9Sstevel@tonic-gate 		if (fd > ctx->fdMax)
9267c478bd9Sstevel@tonic-gate 			ctx->fdMax = fd;
9277c478bd9Sstevel@tonic-gate 	}
9287c478bd9Sstevel@tonic-gate }
9299525b14bSRao Shoaib #endif /* USE_POLL */
9309525b14bSRao Shoaib 
9319525b14bSRao Shoaib /*! \file */
932