1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
3*0Sstevel@tonic-gate  * Use is subject to license terms.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate 
6*0Sstevel@tonic-gate /*
7*0Sstevel@tonic-gate  * Copyright (c) 1995-1999 by Internet Software Consortium
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software for any
10*0Sstevel@tonic-gate  * purpose with or without fee is hereby granted, provided that the above
11*0Sstevel@tonic-gate  * copyright notice and this permission notice appear in all copies.
12*0Sstevel@tonic-gate  *
13*0Sstevel@tonic-gate  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
14*0Sstevel@tonic-gate  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
15*0Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
16*0Sstevel@tonic-gate  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
17*0Sstevel@tonic-gate  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18*0Sstevel@tonic-gate  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19*0Sstevel@tonic-gate  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20*0Sstevel@tonic-gate  * SOFTWARE.
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate 
23*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
24*0Sstevel@tonic-gate 
25*0Sstevel@tonic-gate /* eventlib.c - implement glue for the eventlib
26*0Sstevel@tonic-gate  * vix 09sep95 [initial]
27*0Sstevel@tonic-gate  */
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #if !defined(LINT) && !defined(CODECENTER)
30*0Sstevel@tonic-gate static const char rcsid[] = "$Id: eventlib.c,v 1.48 2002/07/17 07:37:34 marka Exp $";
31*0Sstevel@tonic-gate #endif
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include "port_before.h"
34*0Sstevel@tonic-gate #include "fd_setsize.h"
35*0Sstevel@tonic-gate 
36*0Sstevel@tonic-gate #include <sys/types.h>
37*0Sstevel@tonic-gate #include <sys/time.h>
38*0Sstevel@tonic-gate #include <sys/stat.h>
39*0Sstevel@tonic-gate #ifdef	SUNW_POLL
40*0Sstevel@tonic-gate #include <limits.h>
41*0Sstevel@tonic-gate #endif	/* SUNW_POLL */
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate #include <errno.h>
44*0Sstevel@tonic-gate #include <signal.h>
45*0Sstevel@tonic-gate #include <stdarg.h>
46*0Sstevel@tonic-gate #include <stdlib.h>
47*0Sstevel@tonic-gate #include <unistd.h>
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate #include <isc/eventlib.h>
50*0Sstevel@tonic-gate #include <isc/assertions.h>
51*0Sstevel@tonic-gate #include "eventlib_p.h"
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate #include "port_after.h"
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate #ifdef	SUNW_POLL
56*0Sstevel@tonic-gate #define	pselect	Pselect
57*0Sstevel@tonic-gate #endif	/* SUNW_POLL */
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate /* Forward. */
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate #ifdef NEED_PSELECT
62*0Sstevel@tonic-gate static int		pselect(int, void *, void *, void *,
63*0Sstevel@tonic-gate 				struct timespec *,
64*0Sstevel@tonic-gate 				const sigset_t *);
65*0Sstevel@tonic-gate #endif
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate /* Public. */
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate int
70*0Sstevel@tonic-gate evCreate(evContext *opaqueCtx) {
71*0Sstevel@tonic-gate 	evContext_p *ctx;
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate 	/* Make sure the memory heap is initialized. */
74*0Sstevel@tonic-gate 	if (meminit(0, 0) < 0 && errno != EEXIST)
75*0Sstevel@tonic-gate 		return (-1);
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate 	OKNEW(ctx);
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate 	/* Global. */
80*0Sstevel@tonic-gate 	ctx->cur = NULL;
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate 	/* Debugging. */
83*0Sstevel@tonic-gate 	ctx->debug = 0;
84*0Sstevel@tonic-gate 	ctx->output = NULL;
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate 	/* Connections. */
87*0Sstevel@tonic-gate 	ctx->conns = NULL;
88*0Sstevel@tonic-gate 	INIT_LIST(ctx->accepts);
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate 	/* Files. */
91*0Sstevel@tonic-gate 	ctx->files = NULL;
92*0Sstevel@tonic-gate #ifdef	SUNW_POLL
93*0Sstevel@tonic-gate 	ctx->pollfds = 0;
94*0Sstevel@tonic-gate 	ctx->maxnfds = 0;
95*0Sstevel@tonic-gate 	ctx->firstfd = 0;
96*0Sstevel@tonic-gate 	emulMaskInit(ctx, rdLast, EV_READ, 1);
97*0Sstevel@tonic-gate 	emulMaskInit(ctx, rdNext, EV_READ, 0);
98*0Sstevel@tonic-gate 	emulMaskInit(ctx, wrLast, EV_WRITE, 1);
99*0Sstevel@tonic-gate 	emulMaskInit(ctx, wrNext, EV_WRITE, 0);
100*0Sstevel@tonic-gate 	emulMaskInit(ctx, exLast, EV_EXCEPT, 1);
101*0Sstevel@tonic-gate 	emulMaskInit(ctx, exNext, EV_EXCEPT, 0);
102*0Sstevel@tonic-gate 	emulMaskInit(ctx, nonblockBefore, EV_WASNONBLOCKING, 0);
103*0Sstevel@tonic-gate #endif	/* SUNW_POLL */
104*0Sstevel@tonic-gate 	FD_ZERO(&ctx->rdNext);
105*0Sstevel@tonic-gate 	FD_ZERO(&ctx->wrNext);
106*0Sstevel@tonic-gate 	FD_ZERO(&ctx->exNext);
107*0Sstevel@tonic-gate 	FD_ZERO(&ctx->nonblockBefore);
108*0Sstevel@tonic-gate 	ctx->fdMax = -1;
109*0Sstevel@tonic-gate 	ctx->fdNext = NULL;
110*0Sstevel@tonic-gate 	ctx->fdCount = 0;	/* Invalidate {rd,wr,ex}Last. */
111*0Sstevel@tonic-gate #ifdef	SUNW_POLL
112*0Sstevel@tonic-gate 	ctx->highestFD = INT_MAX;
113*0Sstevel@tonic-gate #else
114*0Sstevel@tonic-gate 	ctx->highestFD = FD_SETSIZE - 1;
115*0Sstevel@tonic-gate #endif	/* SUNW_POLL */
116*0Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
117*0Sstevel@tonic-gate 	ctx->lastFdCount = 0;
118*0Sstevel@tonic-gate #endif
119*0Sstevel@tonic-gate #ifdef	SUNW_POLL
120*0Sstevel@tonic-gate 	ctx->fdTable = 0;
121*0Sstevel@tonic-gate #else
122*0Sstevel@tonic-gate 	memset(ctx->fdTable, 0, sizeof ctx->fdTable);
123*0Sstevel@tonic-gate #endif	/* SUNW_POLL */
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate 	/* Streams. */
126*0Sstevel@tonic-gate 	ctx->streams = NULL;
127*0Sstevel@tonic-gate 	ctx->strDone = NULL;
128*0Sstevel@tonic-gate 	ctx->strLast = NULL;
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 	/* Timers. */
131*0Sstevel@tonic-gate 	ctx->lastEventTime = evNowTime();
132*0Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
133*0Sstevel@tonic-gate 	ctx->lastSelectTime = ctx->lastEventTime;
134*0Sstevel@tonic-gate #endif
135*0Sstevel@tonic-gate 	ctx->timers = evCreateTimers(ctx);
136*0Sstevel@tonic-gate 	if (ctx->timers == NULL)
137*0Sstevel@tonic-gate 		return (-1);
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate 	/* Waits. */
140*0Sstevel@tonic-gate 	ctx->waitLists = NULL;
141*0Sstevel@tonic-gate 	ctx->waitDone.first = ctx->waitDone.last = NULL;
142*0Sstevel@tonic-gate 	ctx->waitDone.prev = ctx->waitDone.next = NULL;
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 	opaqueCtx->opaque = ctx;
145*0Sstevel@tonic-gate 	return (0);
146*0Sstevel@tonic-gate }
147*0Sstevel@tonic-gate 
148*0Sstevel@tonic-gate void
149*0Sstevel@tonic-gate evSetDebug(evContext opaqueCtx, int level, FILE *output) {
150*0Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 	ctx->debug = level;
153*0Sstevel@tonic-gate 	ctx->output = output;
154*0Sstevel@tonic-gate }
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate int
157*0Sstevel@tonic-gate evDestroy(evContext opaqueCtx) {
158*0Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
159*0Sstevel@tonic-gate 	int revs = 424242;	/* Doug Adams. */
160*0Sstevel@tonic-gate 	evWaitList *this_wl, *next_wl;
161*0Sstevel@tonic-gate 	evWait *this_wait, *next_wait;
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 	/* Connections. */
164*0Sstevel@tonic-gate 	while (revs-- > 0 && ctx->conns != NULL) {
165*0Sstevel@tonic-gate 		evConnID id;
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate 		id.opaque = ctx->conns;
168*0Sstevel@tonic-gate 		(void) evCancelConn(opaqueCtx, id);
169*0Sstevel@tonic-gate 	}
170*0Sstevel@tonic-gate 	INSIST(revs >= 0);
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	/* Streams. */
173*0Sstevel@tonic-gate 	while (revs-- > 0 && ctx->streams != NULL) {
174*0Sstevel@tonic-gate 		evStreamID id;
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate 		id.opaque = ctx->streams;
177*0Sstevel@tonic-gate 		(void) evCancelRW(opaqueCtx, id);
178*0Sstevel@tonic-gate 	}
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	/* Files. */
181*0Sstevel@tonic-gate 	while (revs-- > 0 && ctx->files != NULL) {
182*0Sstevel@tonic-gate 		evFileID id;
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 		id.opaque = ctx->files;
185*0Sstevel@tonic-gate 		(void) evDeselectFD(opaqueCtx, id);
186*0Sstevel@tonic-gate 	}
187*0Sstevel@tonic-gate 	INSIST(revs >= 0);
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	/* Timers. */
190*0Sstevel@tonic-gate 	evDestroyTimers(ctx);
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 	/* Waits. */
193*0Sstevel@tonic-gate 	for (this_wl = ctx->waitLists;
194*0Sstevel@tonic-gate 	     revs-- > 0 && this_wl != NULL;
195*0Sstevel@tonic-gate 	     this_wl = next_wl) {
196*0Sstevel@tonic-gate 		next_wl = this_wl->next;
197*0Sstevel@tonic-gate 		for (this_wait = this_wl->first;
198*0Sstevel@tonic-gate 		     revs-- > 0 && this_wait != NULL;
199*0Sstevel@tonic-gate 		     this_wait = next_wait) {
200*0Sstevel@tonic-gate 			next_wait = this_wait->next;
201*0Sstevel@tonic-gate 			FREE(this_wait);
202*0Sstevel@tonic-gate 		}
203*0Sstevel@tonic-gate 		FREE(this_wl);
204*0Sstevel@tonic-gate 	}
205*0Sstevel@tonic-gate 	for (this_wait = ctx->waitDone.first;
206*0Sstevel@tonic-gate 	     revs-- > 0 && this_wait != NULL;
207*0Sstevel@tonic-gate 	     this_wait = next_wait) {
208*0Sstevel@tonic-gate 		next_wait = this_wait->next;
209*0Sstevel@tonic-gate 		FREE(this_wait);
210*0Sstevel@tonic-gate 	}
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	FREE(ctx);
213*0Sstevel@tonic-gate 	return (0);
214*0Sstevel@tonic-gate }
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate int
217*0Sstevel@tonic-gate evGetNext(evContext opaqueCtx, evEvent *opaqueEv, int options) {
218*0Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
219*0Sstevel@tonic-gate 	struct timespec nextTime;
220*0Sstevel@tonic-gate 	evTimer *nextTimer;
221*0Sstevel@tonic-gate 	evEvent_p *new;
222*0Sstevel@tonic-gate 	int x, pselect_errno, timerPast;
223*0Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
224*0Sstevel@tonic-gate 	struct timespec interval;
225*0Sstevel@tonic-gate #endif
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	/* Ensure that exactly one of EV_POLL or EV_WAIT was specified. */
228*0Sstevel@tonic-gate 	x = ((options & EV_POLL) != 0) + ((options & EV_WAIT) != 0);
229*0Sstevel@tonic-gate 	if (x != 1)
230*0Sstevel@tonic-gate 		EV_ERR(EINVAL);
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate 	/* Get the time of day.  We'll do this again after select() blocks. */
233*0Sstevel@tonic-gate 	ctx->lastEventTime = evNowTime();
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate  again:
236*0Sstevel@tonic-gate 	/* Finished accept()'s do not require a select(). */
237*0Sstevel@tonic-gate 	if (!EMPTY(ctx->accepts)) {
238*0Sstevel@tonic-gate 		OKNEW(new);
239*0Sstevel@tonic-gate 		new->type = Accept;
240*0Sstevel@tonic-gate 		new->u.accept.this = HEAD(ctx->accepts);
241*0Sstevel@tonic-gate 		UNLINK(ctx->accepts, HEAD(ctx->accepts), link);
242*0Sstevel@tonic-gate 		opaqueEv->opaque = new;
243*0Sstevel@tonic-gate 		return (0);
244*0Sstevel@tonic-gate 	}
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate 	/* Stream IO does not require a select(). */
247*0Sstevel@tonic-gate 	if (ctx->strDone != NULL) {
248*0Sstevel@tonic-gate 		OKNEW(new);
249*0Sstevel@tonic-gate 		new->type = Stream;
250*0Sstevel@tonic-gate 		new->u.stream.this = ctx->strDone;
251*0Sstevel@tonic-gate 		ctx->strDone = ctx->strDone->nextDone;
252*0Sstevel@tonic-gate 		if (ctx->strDone == NULL)
253*0Sstevel@tonic-gate 			ctx->strLast = NULL;
254*0Sstevel@tonic-gate 		opaqueEv->opaque = new;
255*0Sstevel@tonic-gate 		return (0);
256*0Sstevel@tonic-gate 	}
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 	/* Waits do not require a select(). */
259*0Sstevel@tonic-gate 	if (ctx->waitDone.first != NULL) {
260*0Sstevel@tonic-gate 		OKNEW(new);
261*0Sstevel@tonic-gate 		new->type = Wait;
262*0Sstevel@tonic-gate 		new->u.wait.this = ctx->waitDone.first;
263*0Sstevel@tonic-gate 		ctx->waitDone.first = ctx->waitDone.first->next;
264*0Sstevel@tonic-gate 		if (ctx->waitDone.first == NULL)
265*0Sstevel@tonic-gate 			ctx->waitDone.last = NULL;
266*0Sstevel@tonic-gate 		opaqueEv->opaque = new;
267*0Sstevel@tonic-gate 		return (0);
268*0Sstevel@tonic-gate 	}
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	/* Get the status and content of the next timer. */
271*0Sstevel@tonic-gate 	if ((nextTimer = heap_element(ctx->timers, 1)) != NULL) {
272*0Sstevel@tonic-gate 		nextTime = nextTimer->due;
273*0Sstevel@tonic-gate 		timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
274*0Sstevel@tonic-gate 	} else
275*0Sstevel@tonic-gate 		timerPast = 0;	/* Make gcc happy. */
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 	evPrintf(ctx, 9, "evGetNext: fdCount %d\n", ctx->fdCount);
278*0Sstevel@tonic-gate 	if (ctx->fdCount == 0) {
279*0Sstevel@tonic-gate 		static const struct timespec NoTime = {0, 0L};
280*0Sstevel@tonic-gate 		enum { JustPoll, Block, Timer } m;
281*0Sstevel@tonic-gate 		struct timespec t, *tp;
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 		/* Are there any events at all? */
284*0Sstevel@tonic-gate 		if ((options & EV_WAIT) != 0 && !nextTimer && ctx->fdMax == -1)
285*0Sstevel@tonic-gate 			EV_ERR(ENOENT);
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 		/* Figure out what select()'s timeout parameter should be. */
288*0Sstevel@tonic-gate 		if ((options & EV_POLL) != 0) {
289*0Sstevel@tonic-gate 			m = JustPoll;
290*0Sstevel@tonic-gate 			t = NoTime;
291*0Sstevel@tonic-gate 			tp = &t;
292*0Sstevel@tonic-gate 		} else if (nextTimer == NULL) {
293*0Sstevel@tonic-gate 			m = Block;
294*0Sstevel@tonic-gate 			/* ``t'' unused. */
295*0Sstevel@tonic-gate 			tp = NULL;
296*0Sstevel@tonic-gate 		} else if (timerPast) {
297*0Sstevel@tonic-gate 			m = JustPoll;
298*0Sstevel@tonic-gate 			t = NoTime;
299*0Sstevel@tonic-gate 			tp = &t;
300*0Sstevel@tonic-gate 		} else {
301*0Sstevel@tonic-gate 			m = Timer;
302*0Sstevel@tonic-gate 			/* ``t'' filled in later. */
303*0Sstevel@tonic-gate 			tp = &t;
304*0Sstevel@tonic-gate 		}
305*0Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
306*0Sstevel@tonic-gate 		if (ctx->debug > 0) {
307*0Sstevel@tonic-gate 			interval = evSubTime(ctx->lastEventTime,
308*0Sstevel@tonic-gate 					     ctx->lastSelectTime);
309*0Sstevel@tonic-gate 			if (interval.tv_sec > 0)
310*0Sstevel@tonic-gate 				evPrintf(ctx, 1,
311*0Sstevel@tonic-gate 				   "time between pselect() %u.%09u count %d\n",
312*0Sstevel@tonic-gate 					 interval.tv_sec, interval.tv_nsec,
313*0Sstevel@tonic-gate 					 ctx->lastFdCount);
314*0Sstevel@tonic-gate 		}
315*0Sstevel@tonic-gate #endif
316*0Sstevel@tonic-gate 		do {
317*0Sstevel@tonic-gate #ifdef	SUNW_POLL
318*0Sstevel@tonic-gate 			/*
319*0Sstevel@tonic-gate 			 * The pollfd structure uses separate fields for
320*0Sstevel@tonic-gate 			 * the input and output events (corresponding to
321*0Sstevel@tonic-gate 			 * the ??Next and ??Last fd sets), so there's no
322*0Sstevel@tonic-gate 			 * need to copy one to the other.
323*0Sstevel@tonic-gate 			 */
324*0Sstevel@tonic-gate #else
325*0Sstevel@tonic-gate 			/* XXX need to copy only the bits we are using. */
326*0Sstevel@tonic-gate 			ctx->rdLast = ctx->rdNext;
327*0Sstevel@tonic-gate 			ctx->wrLast = ctx->wrNext;
328*0Sstevel@tonic-gate 			ctx->exLast = ctx->exNext;
329*0Sstevel@tonic-gate #endif	/* SUNW_POLL */
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 			if (m == Timer) {
332*0Sstevel@tonic-gate 				INSIST(tp == &t);
333*0Sstevel@tonic-gate 				t = evSubTime(nextTime, ctx->lastEventTime);
334*0Sstevel@tonic-gate 			}
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate #ifdef SUNW_POLL
337*0Sstevel@tonic-gate #else
338*0Sstevel@tonic-gate 			evPrintf(ctx, 4,
339*0Sstevel@tonic-gate 				"pselect(%d, 0x%lx, 0x%lx, 0x%lx, %ld.%09ld)\n",
340*0Sstevel@tonic-gate 				 ctx->fdMax+1,
341*0Sstevel@tonic-gate 				 (u_long)ctx->rdLast.fds_bits[0],
342*0Sstevel@tonic-gate 				 (u_long)ctx->wrLast.fds_bits[0],
343*0Sstevel@tonic-gate 				 (u_long)ctx->exLast.fds_bits[0],
344*0Sstevel@tonic-gate 				 tp ? (long)tp->tv_sec : -1L,
345*0Sstevel@tonic-gate 				 tp ? tp->tv_nsec : -1);
346*0Sstevel@tonic-gate #endif
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate 			/* XXX should predict system's earliness and adjust. */
349*0Sstevel@tonic-gate 			x = pselect(ctx->fdMax+1,
350*0Sstevel@tonic-gate 				    &ctx->rdLast, &ctx->wrLast, &ctx->exLast,
351*0Sstevel@tonic-gate 				    tp, NULL);
352*0Sstevel@tonic-gate 			pselect_errno = errno;
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate #ifdef SUNW_POLL
355*0Sstevel@tonic-gate 			evPrintf(ctx, 4, "poll() returns %d (err: %s)\n",
356*0Sstevel@tonic-gate 				 x, (x == -1) ? strerror(errno) : "none");
357*0Sstevel@tonic-gate #else
358*0Sstevel@tonic-gate 			evPrintf(ctx, 4, "select() returns %d (err: %s)\n",
359*0Sstevel@tonic-gate 				 x, (x == -1) ? strerror(errno) : "none");
360*0Sstevel@tonic-gate #endif /* SUNW_POLL */
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 			/* Anything but a poll can change the time. */
363*0Sstevel@tonic-gate 			if (m != JustPoll)
364*0Sstevel@tonic-gate 				ctx->lastEventTime = evNowTime();
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 			/* Select() likes to finish about 10ms early. */
367*0Sstevel@tonic-gate 		} while (x == 0 && m == Timer &&
368*0Sstevel@tonic-gate 			 evCmpTime(ctx->lastEventTime, nextTime) < 0);
369*0Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
370*0Sstevel@tonic-gate 		ctx->lastSelectTime = ctx->lastEventTime;
371*0Sstevel@tonic-gate #endif
372*0Sstevel@tonic-gate 		if (x < 0) {
373*0Sstevel@tonic-gate 			if (pselect_errno == EINTR) {
374*0Sstevel@tonic-gate 				if ((options & EV_NULL) != 0)
375*0Sstevel@tonic-gate 					goto again;
376*0Sstevel@tonic-gate 				OKNEW(new);
377*0Sstevel@tonic-gate 				new->type = Null;
378*0Sstevel@tonic-gate 				/* No data. */
379*0Sstevel@tonic-gate 				opaqueEv->opaque = new;
380*0Sstevel@tonic-gate 				return (0);
381*0Sstevel@tonic-gate 			}
382*0Sstevel@tonic-gate 			if (pselect_errno == EBADF) {
383*0Sstevel@tonic-gate 				for (x = 0; x <= ctx->fdMax; x++) {
384*0Sstevel@tonic-gate 					struct stat sb;
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate 					if (FD_ISSET(x, &ctx->rdNext) == 0 &&
387*0Sstevel@tonic-gate 					    FD_ISSET(x, &ctx->wrNext) == 0 &&
388*0Sstevel@tonic-gate 					    FD_ISSET(x, &ctx->exNext) == 0)
389*0Sstevel@tonic-gate 						continue;
390*0Sstevel@tonic-gate 					if (fstat(x, &sb) == -1 &&
391*0Sstevel@tonic-gate 					    errno == EBADF)
392*0Sstevel@tonic-gate 						evPrintf(ctx, 1, "EBADF: %d\n",
393*0Sstevel@tonic-gate 							 x);
394*0Sstevel@tonic-gate 				}
395*0Sstevel@tonic-gate 				abort();
396*0Sstevel@tonic-gate 			}
397*0Sstevel@tonic-gate 			EV_ERR(pselect_errno);
398*0Sstevel@tonic-gate 		}
399*0Sstevel@tonic-gate 		if (x == 0 && (nextTimer == NULL || !timerPast) &&
400*0Sstevel@tonic-gate 		    (options & EV_POLL))
401*0Sstevel@tonic-gate 			EV_ERR(EWOULDBLOCK);
402*0Sstevel@tonic-gate 		ctx->fdCount = x;
403*0Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
404*0Sstevel@tonic-gate 		ctx->lastFdCount = x;
405*0Sstevel@tonic-gate #endif
406*0Sstevel@tonic-gate 	}
407*0Sstevel@tonic-gate 	INSIST(nextTimer || ctx->fdCount);
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate 	/* Timers go first since we'd like them to be accurate. */
410*0Sstevel@tonic-gate 	if (nextTimer && !timerPast) {
411*0Sstevel@tonic-gate 		/* Has anything happened since we blocked? */
412*0Sstevel@tonic-gate 		timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
413*0Sstevel@tonic-gate 	}
414*0Sstevel@tonic-gate 	if (nextTimer && timerPast) {
415*0Sstevel@tonic-gate 		OKNEW(new);
416*0Sstevel@tonic-gate 		new->type = Timer;
417*0Sstevel@tonic-gate 		new->u.timer.this = nextTimer;
418*0Sstevel@tonic-gate 		opaqueEv->opaque = new;
419*0Sstevel@tonic-gate 		return (0);
420*0Sstevel@tonic-gate 	}
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 	/* No timers, so there should be a ready file descriptor. */
423*0Sstevel@tonic-gate 	x = 0;
424*0Sstevel@tonic-gate 	while (ctx->fdCount > 0) {
425*0Sstevel@tonic-gate 		evFile *fid;
426*0Sstevel@tonic-gate 		int fd, eventmask;
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate 		if (ctx->fdNext == NULL) {
429*0Sstevel@tonic-gate 			if (++x == 2) {
430*0Sstevel@tonic-gate 				/*
431*0Sstevel@tonic-gate 				 * Hitting the end twice means that the last
432*0Sstevel@tonic-gate 				 * select() found some FD's which have since
433*0Sstevel@tonic-gate 				 * been deselected.
434*0Sstevel@tonic-gate 				 *
435*0Sstevel@tonic-gate 				 * On some systems, the count returned by
436*0Sstevel@tonic-gate 				 * selects is the total number of bits in
437*0Sstevel@tonic-gate 				 * all masks that are set, and on others it's
438*0Sstevel@tonic-gate 				 * the number of fd's that have some bit set,
439*0Sstevel@tonic-gate 				 * and on others, it's just broken.  We
440*0Sstevel@tonic-gate 				 * always assume that it's the number of
441*0Sstevel@tonic-gate 				 * bits set in all masks, because that's what
442*0Sstevel@tonic-gate 				 * the man page says it should do, and
443*0Sstevel@tonic-gate 				 * the worst that can happen is we do an
444*0Sstevel@tonic-gate 				 * extra select().
445*0Sstevel@tonic-gate 				 */
446*0Sstevel@tonic-gate 				ctx->fdCount = 0;
447*0Sstevel@tonic-gate 				break;
448*0Sstevel@tonic-gate 			}
449*0Sstevel@tonic-gate 			ctx->fdNext = ctx->files;
450*0Sstevel@tonic-gate 		}
451*0Sstevel@tonic-gate 		fid = ctx->fdNext;
452*0Sstevel@tonic-gate 		ctx->fdNext = fid->next;
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 		fd = fid->fd;
455*0Sstevel@tonic-gate 		eventmask = 0;
456*0Sstevel@tonic-gate 		if (FD_ISSET(fd, &ctx->rdLast))
457*0Sstevel@tonic-gate 			eventmask |= EV_READ;
458*0Sstevel@tonic-gate 		if (FD_ISSET(fd, &ctx->wrLast))
459*0Sstevel@tonic-gate 			eventmask |= EV_WRITE;
460*0Sstevel@tonic-gate 		if (FD_ISSET(fd, &ctx->exLast))
461*0Sstevel@tonic-gate 			eventmask |= EV_EXCEPT;
462*0Sstevel@tonic-gate 		eventmask &= fid->eventmask;
463*0Sstevel@tonic-gate 		if (eventmask != 0) {
464*0Sstevel@tonic-gate 			if ((eventmask & EV_READ) != 0) {
465*0Sstevel@tonic-gate 				FD_CLR(fd, &ctx->rdLast);
466*0Sstevel@tonic-gate 				ctx->fdCount--;
467*0Sstevel@tonic-gate 			}
468*0Sstevel@tonic-gate 			if ((eventmask & EV_WRITE) != 0) {
469*0Sstevel@tonic-gate 				FD_CLR(fd, &ctx->wrLast);
470*0Sstevel@tonic-gate 				ctx->fdCount--;
471*0Sstevel@tonic-gate 			}
472*0Sstevel@tonic-gate 			if ((eventmask & EV_EXCEPT) != 0) {
473*0Sstevel@tonic-gate 				FD_CLR(fd, &ctx->exLast);
474*0Sstevel@tonic-gate 				ctx->fdCount--;
475*0Sstevel@tonic-gate 			}
476*0Sstevel@tonic-gate 			OKNEW(new);
477*0Sstevel@tonic-gate 			new->type = File;
478*0Sstevel@tonic-gate 			new->u.file.this = fid;
479*0Sstevel@tonic-gate 			new->u.file.eventmask = eventmask;
480*0Sstevel@tonic-gate 			opaqueEv->opaque = new;
481*0Sstevel@tonic-gate 			return (0);
482*0Sstevel@tonic-gate 		}
483*0Sstevel@tonic-gate 	}
484*0Sstevel@tonic-gate 	if (ctx->fdCount < 0) {
485*0Sstevel@tonic-gate 		/*
486*0Sstevel@tonic-gate 		 * select()'s count is off on a number of systems, and
487*0Sstevel@tonic-gate 		 * can result in fdCount < 0.
488*0Sstevel@tonic-gate 		 */
489*0Sstevel@tonic-gate 		evPrintf(ctx, 4, "fdCount < 0 (%d)\n", ctx->fdCount);
490*0Sstevel@tonic-gate 		ctx->fdCount = 0;
491*0Sstevel@tonic-gate 	}
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate 	/* We get here if the caller deselect()'s an FD. Gag me with a goto. */
494*0Sstevel@tonic-gate 	goto again;
495*0Sstevel@tonic-gate }
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate int
498*0Sstevel@tonic-gate evDispatch(evContext opaqueCtx, evEvent opaqueEv) {
499*0Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
500*0Sstevel@tonic-gate 	evEvent_p *ev = opaqueEv.opaque;
501*0Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
502*0Sstevel@tonic-gate 	void *func;
503*0Sstevel@tonic-gate 	struct timespec start_time;
504*0Sstevel@tonic-gate 	struct timespec interval;
505*0Sstevel@tonic-gate #endif
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
508*0Sstevel@tonic-gate 	if (ctx->debug > 0)
509*0Sstevel@tonic-gate 		start_time = evNowTime();
510*0Sstevel@tonic-gate #endif
511*0Sstevel@tonic-gate 	ctx->cur = ev;
512*0Sstevel@tonic-gate 	switch (ev->type) {
513*0Sstevel@tonic-gate 	    case Accept: {
514*0Sstevel@tonic-gate 		evAccept *this = ev->u.accept.this;
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate 		evPrintf(ctx, 5,
517*0Sstevel@tonic-gate 			"Dispatch.Accept: fd %d -> %d, func %p, uap %p\n",
518*0Sstevel@tonic-gate 			 this->conn->fd, this->fd,
519*0Sstevel@tonic-gate 			 this->conn->func, this->conn->uap);
520*0Sstevel@tonic-gate 		errno = this->ioErrno;
521*0Sstevel@tonic-gate 		(this->conn->func)(opaqueCtx, this->conn->uap, this->fd,
522*0Sstevel@tonic-gate 				   &this->la, this->lalen,
523*0Sstevel@tonic-gate 				   &this->ra, this->ralen);
524*0Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
525*0Sstevel@tonic-gate 		func = this->conn->func;
526*0Sstevel@tonic-gate #endif
527*0Sstevel@tonic-gate 		break;
528*0Sstevel@tonic-gate 	    }
529*0Sstevel@tonic-gate 	    case File: {
530*0Sstevel@tonic-gate 		evFile *this = ev->u.file.this;
531*0Sstevel@tonic-gate 		int eventmask = ev->u.file.eventmask;
532*0Sstevel@tonic-gate 
533*0Sstevel@tonic-gate 		evPrintf(ctx, 5,
534*0Sstevel@tonic-gate 			"Dispatch.File: fd %d, mask 0x%x, func %p, uap %p\n",
535*0Sstevel@tonic-gate 			 this->fd, this->eventmask, this->func, this->uap);
536*0Sstevel@tonic-gate 		(this->func)(opaqueCtx, this->uap, this->fd, eventmask);
537*0Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
538*0Sstevel@tonic-gate 		func = this->func;
539*0Sstevel@tonic-gate #endif
540*0Sstevel@tonic-gate 		break;
541*0Sstevel@tonic-gate 	    }
542*0Sstevel@tonic-gate 	    case Stream: {
543*0Sstevel@tonic-gate 		evStream *this = ev->u.stream.this;
544*0Sstevel@tonic-gate 
545*0Sstevel@tonic-gate 		evPrintf(ctx, 5,
546*0Sstevel@tonic-gate 			 "Dispatch.Stream: fd %d, func %p, uap %p\n",
547*0Sstevel@tonic-gate 			 this->fd, this->func, this->uap);
548*0Sstevel@tonic-gate 		errno = this->ioErrno;
549*0Sstevel@tonic-gate 		(this->func)(opaqueCtx, this->uap, this->fd, this->ioDone);
550*0Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
551*0Sstevel@tonic-gate 		func = this->func;
552*0Sstevel@tonic-gate #endif
553*0Sstevel@tonic-gate 		break;
554*0Sstevel@tonic-gate 	    }
555*0Sstevel@tonic-gate 	    case Timer: {
556*0Sstevel@tonic-gate 		evTimer *this = ev->u.timer.this;
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate 		evPrintf(ctx, 5, "Dispatch.Timer: func %p, uap %p\n",
559*0Sstevel@tonic-gate 			 this->func, this->uap);
560*0Sstevel@tonic-gate 		(this->func)(opaqueCtx, this->uap, this->due, this->inter);
561*0Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
562*0Sstevel@tonic-gate 		func = this->func;
563*0Sstevel@tonic-gate #endif
564*0Sstevel@tonic-gate 		break;
565*0Sstevel@tonic-gate 	    }
566*0Sstevel@tonic-gate 	    case Wait: {
567*0Sstevel@tonic-gate 		evWait *this = ev->u.wait.this;
568*0Sstevel@tonic-gate 
569*0Sstevel@tonic-gate 		evPrintf(ctx, 5,
570*0Sstevel@tonic-gate 			 "Dispatch.Wait: tag %p, func %p, uap %p\n",
571*0Sstevel@tonic-gate 			 this->tag, this->func, this->uap);
572*0Sstevel@tonic-gate 		(this->func)(opaqueCtx, this->uap, this->tag);
573*0Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
574*0Sstevel@tonic-gate 		func = this->func;
575*0Sstevel@tonic-gate #endif
576*0Sstevel@tonic-gate 		break;
577*0Sstevel@tonic-gate 	    }
578*0Sstevel@tonic-gate 	    case Null: {
579*0Sstevel@tonic-gate 		/* No work. */
580*0Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
581*0Sstevel@tonic-gate 		func = NULL;
582*0Sstevel@tonic-gate #endif
583*0Sstevel@tonic-gate 		break;
584*0Sstevel@tonic-gate 	    }
585*0Sstevel@tonic-gate 	    default: {
586*0Sstevel@tonic-gate 		abort();
587*0Sstevel@tonic-gate 	    }
588*0Sstevel@tonic-gate 	}
589*0Sstevel@tonic-gate #ifdef EVENTLIB_TIME_CHECKS
590*0Sstevel@tonic-gate 	if (ctx->debug > 0) {
591*0Sstevel@tonic-gate 		interval = evSubTime(evNowTime(), start_time);
592*0Sstevel@tonic-gate 		/*
593*0Sstevel@tonic-gate 		 * Complain if it took longer than 50 milliseconds.
594*0Sstevel@tonic-gate 		 *
595*0Sstevel@tonic-gate 		 * We call getuid() to make an easy to find mark in a kernel
596*0Sstevel@tonic-gate 		 * trace.
597*0Sstevel@tonic-gate 		 */
598*0Sstevel@tonic-gate 		if (interval.tv_sec > 0 || interval.tv_nsec > 50000000)
599*0Sstevel@tonic-gate 			evPrintf(ctx, 1,
600*0Sstevel@tonic-gate 			 "dispatch interval %u.%09u uid %d type %d func %p\n",
601*0Sstevel@tonic-gate 				 interval.tv_sec, interval.tv_nsec,
602*0Sstevel@tonic-gate 				 getuid(), ev->type, func);
603*0Sstevel@tonic-gate 	}
604*0Sstevel@tonic-gate #endif
605*0Sstevel@tonic-gate 	ctx->cur = NULL;
606*0Sstevel@tonic-gate 	evDrop(opaqueCtx, opaqueEv);
607*0Sstevel@tonic-gate 	return (0);
608*0Sstevel@tonic-gate }
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate void
611*0Sstevel@tonic-gate evDrop(evContext opaqueCtx, evEvent opaqueEv) {
612*0Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
613*0Sstevel@tonic-gate 	evEvent_p *ev = opaqueEv.opaque;
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate 	switch (ev->type) {
616*0Sstevel@tonic-gate 	    case Accept: {
617*0Sstevel@tonic-gate 		FREE(ev->u.accept.this);
618*0Sstevel@tonic-gate 		break;
619*0Sstevel@tonic-gate 	    }
620*0Sstevel@tonic-gate 	    case File: {
621*0Sstevel@tonic-gate 		/* No work. */
622*0Sstevel@tonic-gate 		break;
623*0Sstevel@tonic-gate 	    }
624*0Sstevel@tonic-gate 	    case Stream: {
625*0Sstevel@tonic-gate 		evStreamID id;
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 		id.opaque = ev->u.stream.this;
628*0Sstevel@tonic-gate 		(void) evCancelRW(opaqueCtx, id);
629*0Sstevel@tonic-gate 		break;
630*0Sstevel@tonic-gate 	    }
631*0Sstevel@tonic-gate 	    case Timer: {
632*0Sstevel@tonic-gate 		evTimer *this = ev->u.timer.this;
633*0Sstevel@tonic-gate 		evTimerID opaque;
634*0Sstevel@tonic-gate 
635*0Sstevel@tonic-gate 		/* Check to see whether the user func cleared the timer. */
636*0Sstevel@tonic-gate 		if (heap_element(ctx->timers, this->index) != this) {
637*0Sstevel@tonic-gate 			evPrintf(ctx, 5, "Dispatch.Timer: timer rm'd?\n");
638*0Sstevel@tonic-gate 			break;
639*0Sstevel@tonic-gate 		}
640*0Sstevel@tonic-gate 		/*
641*0Sstevel@tonic-gate 		 * Timer is still there.  Delete it if it has expired,
642*0Sstevel@tonic-gate 		 * otherwise set it according to its next interval.
643*0Sstevel@tonic-gate 		 */
644*0Sstevel@tonic-gate 		if (this->inter.tv_sec == 0 && this->inter.tv_nsec == 0L) {
645*0Sstevel@tonic-gate 			opaque.opaque = this;
646*0Sstevel@tonic-gate 			(void) evClearTimer(opaqueCtx, opaque);
647*0Sstevel@tonic-gate 		} else {
648*0Sstevel@tonic-gate 			opaque.opaque = this;
649*0Sstevel@tonic-gate 			(void) evResetTimer(opaqueCtx, opaque, this->func,
650*0Sstevel@tonic-gate 					    this->uap,
651*0Sstevel@tonic-gate 					    evAddTime(ctx->lastEventTime,
652*0Sstevel@tonic-gate 						      this->inter),
653*0Sstevel@tonic-gate 					    this->inter);
654*0Sstevel@tonic-gate 		}
655*0Sstevel@tonic-gate 		break;
656*0Sstevel@tonic-gate 	    }
657*0Sstevel@tonic-gate 	    case Wait: {
658*0Sstevel@tonic-gate 		FREE(ev->u.wait.this);
659*0Sstevel@tonic-gate 		break;
660*0Sstevel@tonic-gate 	    }
661*0Sstevel@tonic-gate 	    case Null: {
662*0Sstevel@tonic-gate 		/* No work. */
663*0Sstevel@tonic-gate 		break;
664*0Sstevel@tonic-gate 	    }
665*0Sstevel@tonic-gate 	    default: {
666*0Sstevel@tonic-gate 		abort();
667*0Sstevel@tonic-gate 	    }
668*0Sstevel@tonic-gate 	}
669*0Sstevel@tonic-gate 	FREE(ev);
670*0Sstevel@tonic-gate }
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate int
673*0Sstevel@tonic-gate evMainLoop(evContext opaqueCtx) {
674*0Sstevel@tonic-gate 	evEvent event;
675*0Sstevel@tonic-gate 	int x;
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate 	while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0)
678*0Sstevel@tonic-gate 		if ((x = evDispatch(opaqueCtx, event)) < 0)
679*0Sstevel@tonic-gate 			break;
680*0Sstevel@tonic-gate 	return (x);
681*0Sstevel@tonic-gate }
682*0Sstevel@tonic-gate 
683*0Sstevel@tonic-gate int
684*0Sstevel@tonic-gate evHighestFD(evContext opaqueCtx) {
685*0Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
686*0Sstevel@tonic-gate 
687*0Sstevel@tonic-gate 	return (ctx->highestFD);
688*0Sstevel@tonic-gate }
689*0Sstevel@tonic-gate 
690*0Sstevel@tonic-gate void
691*0Sstevel@tonic-gate evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) {
692*0Sstevel@tonic-gate 	va_list ap;
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate 	va_start(ap, fmt);
695*0Sstevel@tonic-gate 	if (ctx->output != NULL && ctx->debug >= level) {
696*0Sstevel@tonic-gate 		vfprintf(ctx->output, fmt, ap);
697*0Sstevel@tonic-gate 		fflush(ctx->output);
698*0Sstevel@tonic-gate 	}
699*0Sstevel@tonic-gate 	va_end(ap);
700*0Sstevel@tonic-gate }
701*0Sstevel@tonic-gate 
702*0Sstevel@tonic-gate #ifdef NEED_PSELECT
703*0Sstevel@tonic-gate /* XXX needs to move to the porting library. */
704*0Sstevel@tonic-gate static int
705*0Sstevel@tonic-gate pselect(int nfds, void *rfds, void *wfds, void *efds,
706*0Sstevel@tonic-gate 	struct timespec *tsp,
707*0Sstevel@tonic-gate 	const sigset_t *sigmask)
708*0Sstevel@tonic-gate {
709*0Sstevel@tonic-gate 	struct timeval tv, *tvp;
710*0Sstevel@tonic-gate 	sigset_t sigs;
711*0Sstevel@tonic-gate 	int n;
712*0Sstevel@tonic-gate #ifdef SUNW_POLL
713*0Sstevel@tonic-gate 	int		polltimeout = INFTIM;
714*0Sstevel@tonic-gate 	evContext_p	*ctx;
715*0Sstevel@tonic-gate 	struct pollfd	*fds;
716*0Sstevel@tonic-gate 	nfds_t		pnfds;
717*0Sstevel@tonic-gate #endif
718*0Sstevel@tonic-gate 
719*0Sstevel@tonic-gate 	if (tsp) {
720*0Sstevel@tonic-gate 		tvp = &tv;
721*0Sstevel@tonic-gate 		tv = evTimeVal(*tsp);
722*0Sstevel@tonic-gate #ifdef SUNW_POLL
723*0Sstevel@tonic-gate 		polltimeout = 1000*tv.tv_sec + tv.tv_usec/1000;
724*0Sstevel@tonic-gate #endif
725*0Sstevel@tonic-gate 	} else
726*0Sstevel@tonic-gate 		tvp = NULL;
727*0Sstevel@tonic-gate 	if (sigmask)
728*0Sstevel@tonic-gate 		sigprocmask(SIG_SETMASK, sigmask, &sigs);
729*0Sstevel@tonic-gate #ifdef SUNW_POLL
730*0Sstevel@tonic-gate 	/*
731*0Sstevel@tonic-gate 	 * rfds, wfds, and efds should all be from the same evContext_p,
732*0Sstevel@tonic-gate 	 * so any of them will do. If they're all NULL, the caller is
733*0Sstevel@tonic-gate 	 * presumably calling us to block.
734*0Sstevel@tonic-gate 	 */
735*0Sstevel@tonic-gate 	if (rfds != 0)
736*0Sstevel@tonic-gate 		ctx = ((__evEmulMask *)rfds)->ctx;
737*0Sstevel@tonic-gate 	else if (wfds != 0)
738*0Sstevel@tonic-gate 		ctx = ((__evEmulMask *)wfds)->ctx;
739*0Sstevel@tonic-gate 	else if (efds != 0)
740*0Sstevel@tonic-gate 		ctx = ((__evEmulMask *)efds)->ctx;
741*0Sstevel@tonic-gate 	else
742*0Sstevel@tonic-gate 		ctx = 0;
743*0Sstevel@tonic-gate 	if (ctx != 0) {
744*0Sstevel@tonic-gate 		fds = &(ctx->pollfds[ctx->firstfd]);
745*0Sstevel@tonic-gate 		pnfds = ctx->fdMax - ctx->firstfd + 1;
746*0Sstevel@tonic-gate 	} else {
747*0Sstevel@tonic-gate 		fds = 0;
748*0Sstevel@tonic-gate 		pnfds = 0;
749*0Sstevel@tonic-gate 	}
750*0Sstevel@tonic-gate 	n = poll(fds, pnfds, polltimeout);
751*0Sstevel@tonic-gate 	/*
752*0Sstevel@tonic-gate 	 * pselect() should return the total number of events on the file
753*0Sstevel@tonic-gate 	 * descriptors, not just the count of fd:s with activity. Hence,
754*0Sstevel@tonic-gate 	 * traverse the pollfds array and count the events.
755*0Sstevel@tonic-gate 	 */
756*0Sstevel@tonic-gate 	if (n > 0) {
757*0Sstevel@tonic-gate 		int	i, e;
758*0Sstevel@tonic-gate 		for (e = 0, i = ctx->firstfd; i <= ctx->fdMax; i++) {
759*0Sstevel@tonic-gate 			if (ctx->pollfds[i].fd < 0)
760*0Sstevel@tonic-gate 				continue;
761*0Sstevel@tonic-gate 			if (FD_ISSET(i, &ctx->rdLast))
762*0Sstevel@tonic-gate 				e++;
763*0Sstevel@tonic-gate 			if (FD_ISSET(i, &ctx->wrLast))
764*0Sstevel@tonic-gate 				e++;
765*0Sstevel@tonic-gate 			if (FD_ISSET(i, &ctx->exLast))
766*0Sstevel@tonic-gate 				e++;
767*0Sstevel@tonic-gate 		}
768*0Sstevel@tonic-gate 		n = e;
769*0Sstevel@tonic-gate 	}
770*0Sstevel@tonic-gate #else
771*0Sstevel@tonic-gate 	n = select(nfds, rfds, wfds, efds, tvp);
772*0Sstevel@tonic-gate #endif	/* SUNW_POLL */
773*0Sstevel@tonic-gate 	if (sigmask)
774*0Sstevel@tonic-gate 		sigprocmask(SIG_SETMASK, &sigs, NULL);
775*0Sstevel@tonic-gate 	if (tsp)
776*0Sstevel@tonic-gate 		*tsp = evTimeSpec(tv);
777*0Sstevel@tonic-gate 	return (n);
778*0Sstevel@tonic-gate }
779*0Sstevel@tonic-gate #endif
780*0Sstevel@tonic-gate 
781*0Sstevel@tonic-gate #ifdef SUNW_POLL
782*0Sstevel@tonic-gate void
783*0Sstevel@tonic-gate evPollfdRealloc(evContext_p *ctx, int pollfd_chunk_size, int fd) {
784*0Sstevel@tonic-gate 
785*0Sstevel@tonic-gate 	int	old_maxnfds = ctx->maxnfds;
786*0Sstevel@tonic-gate 	int	i;
787*0Sstevel@tonic-gate 
788*0Sstevel@tonic-gate 	if (fd < old_maxnfds)
789*0Sstevel@tonic-gate 		return;
790*0Sstevel@tonic-gate 
791*0Sstevel@tonic-gate 	/* Don't allow ridiculously small values for pollfd_chunk_size */
792*0Sstevel@tonic-gate 	if (pollfd_chunk_size < 20)
793*0Sstevel@tonic-gate 		pollfd_chunk_size = 20;
794*0Sstevel@tonic-gate 
795*0Sstevel@tonic-gate 	ctx->maxnfds = (1 + (fd/pollfd_chunk_size)) * pollfd_chunk_size;
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate 	ctx->pollfds = realloc(ctx->pollfds,
798*0Sstevel@tonic-gate 				ctx->maxnfds * sizeof(*ctx->pollfds));
799*0Sstevel@tonic-gate 	ctx->fdTable = realloc(ctx->fdTable,
800*0Sstevel@tonic-gate 				ctx->maxnfds * sizeof(*ctx->fdTable));
801*0Sstevel@tonic-gate 
802*0Sstevel@tonic-gate 	if (ctx->pollfds == 0 || ctx->fdTable == 0) {
803*0Sstevel@tonic-gate 		evPrintf(ctx, 2, "pollfd() realloc (%lu) failed\n",
804*0Sstevel@tonic-gate 			ctx->maxnfds*sizeof(struct pollfd));
805*0Sstevel@tonic-gate 		exit(1);
806*0Sstevel@tonic-gate 	}
807*0Sstevel@tonic-gate 
808*0Sstevel@tonic-gate 	for (i = old_maxnfds; i < ctx->maxnfds; i++) {
809*0Sstevel@tonic-gate 		ctx->pollfds[i].fd = -1;
810*0Sstevel@tonic-gate 		ctx->pollfds[i].events = 0;
811*0Sstevel@tonic-gate 		ctx->fdTable[i] = 0;
812*0Sstevel@tonic-gate 	}
813*0Sstevel@tonic-gate }
814*0Sstevel@tonic-gate 
815*0Sstevel@tonic-gate /*
816*0Sstevel@tonic-gate  * Neither evPollfdAdd() nor evPollfdDel() are needed anymore. We keep
817*0Sstevel@tonic-gate  * them as no-ops for now so that the in.named code doesn't have to change.
818*0Sstevel@tonic-gate  */
819*0Sstevel@tonic-gate void
820*0Sstevel@tonic-gate evPollfdAdd(evContext opaqueCtx, int pollfd_chunk_size, int fd, short events)
821*0Sstevel@tonic-gate {
822*0Sstevel@tonic-gate }
823*0Sstevel@tonic-gate 
824*0Sstevel@tonic-gate void
825*0Sstevel@tonic-gate evPollfdDel(evContext opaqueCtx, int fd)
826*0Sstevel@tonic-gate {
827*0Sstevel@tonic-gate }
828*0Sstevel@tonic-gate 
829*0Sstevel@tonic-gate /* Find the appropriate 'events' or 'revents' field in the pollfds array */
830*0Sstevel@tonic-gate short *
831*0Sstevel@tonic-gate __fd_eventfield(int fd, __evEmulMask *maskp) {
832*0Sstevel@tonic-gate 
833*0Sstevel@tonic-gate 	evContext_p	*ctx = (evContext_p *)maskp->ctx;
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 	if (!maskp->result || maskp->type == EV_WASNONBLOCKING)
836*0Sstevel@tonic-gate 		return (&(ctx->pollfds[fd].events));
837*0Sstevel@tonic-gate 	else
838*0Sstevel@tonic-gate 		return (&(ctx->pollfds[fd].revents));
839*0Sstevel@tonic-gate }
840*0Sstevel@tonic-gate 
841*0Sstevel@tonic-gate /* Translate to poll(2) event */
842*0Sstevel@tonic-gate short
843*0Sstevel@tonic-gate __poll_event(__evEmulMask *maskp) {
844*0Sstevel@tonic-gate 
845*0Sstevel@tonic-gate 	switch ((maskp)->type) {
846*0Sstevel@tonic-gate 	case EV_READ:
847*0Sstevel@tonic-gate 		return (POLLRDNORM);
848*0Sstevel@tonic-gate 	case EV_WRITE:
849*0Sstevel@tonic-gate 		return (POLLWRNORM);
850*0Sstevel@tonic-gate 	case EV_EXCEPT:
851*0Sstevel@tonic-gate 		return (POLLRDBAND | POLLPRI | POLLWRBAND);
852*0Sstevel@tonic-gate 	case EV_WASNONBLOCKING:
853*0Sstevel@tonic-gate 		return (POLLHUP);
854*0Sstevel@tonic-gate 	default:
855*0Sstevel@tonic-gate 		return (0);
856*0Sstevel@tonic-gate 	}
857*0Sstevel@tonic-gate }
858*0Sstevel@tonic-gate 
859*0Sstevel@tonic-gate /*
860*0Sstevel@tonic-gate  * Clear the events corresponding to the specified mask. If this leaves
861*0Sstevel@tonic-gate  * the events mask empty (apart from the POLLHUP bit), set the fd field
862*0Sstevel@tonic-gate  * to -1 so that poll(2) will ignore this fd.
863*0Sstevel@tonic-gate  */
864*0Sstevel@tonic-gate void
865*0Sstevel@tonic-gate __fd_clr(int fd, __evEmulMask *maskp) {
866*0Sstevel@tonic-gate 
867*0Sstevel@tonic-gate 	evContext_p	*ctx = maskp->ctx;
868*0Sstevel@tonic-gate 
869*0Sstevel@tonic-gate 	*__fd_eventfield(fd, maskp) &= ~__poll_event(maskp);
870*0Sstevel@tonic-gate 	if ((ctx->pollfds[fd].events & ~POLLHUP) == 0) {
871*0Sstevel@tonic-gate 		ctx->pollfds[fd].fd = -1;
872*0Sstevel@tonic-gate 		for ( ; ctx->fdMax > 0 && ctx->pollfds[ctx->fdMax].fd < 0;
873*0Sstevel@tonic-gate 			ctx->fdMax--);
874*0Sstevel@tonic-gate 		for ( ; ctx->firstfd <= ctx->fdMax &&
875*0Sstevel@tonic-gate 			ctx->pollfds[ctx->firstfd].fd < 0;
876*0Sstevel@tonic-gate 			ctx->firstfd++);
877*0Sstevel@tonic-gate 	}
878*0Sstevel@tonic-gate }
879*0Sstevel@tonic-gate 
880*0Sstevel@tonic-gate /*
881*0Sstevel@tonic-gate  * Set the events bit(s) corresponding to the specified mask. If the events
882*0Sstevel@tonic-gate  * field has any other bits than POLLHUP set, also set the fd field so that
883*0Sstevel@tonic-gate  * poll(2) will watch this fd.
884*0Sstevel@tonic-gate  */
885*0Sstevel@tonic-gate void
886*0Sstevel@tonic-gate __fd_set(int fd, __evEmulMask *maskp) {
887*0Sstevel@tonic-gate 
888*0Sstevel@tonic-gate 	evContext_p	*ctx = maskp->ctx;
889*0Sstevel@tonic-gate 
890*0Sstevel@tonic-gate 	*__fd_eventfield(fd, maskp) |= __poll_event(maskp);
891*0Sstevel@tonic-gate 	if ((ctx->pollfds[fd].events & ~POLLHUP) != 0) {
892*0Sstevel@tonic-gate 		ctx->pollfds[fd].fd = fd;
893*0Sstevel@tonic-gate 		if (fd < ctx->firstfd || ctx->firstfd == 0)
894*0Sstevel@tonic-gate 			ctx->firstfd = fd;
895*0Sstevel@tonic-gate 		if (fd > ctx->fdMax)
896*0Sstevel@tonic-gate 			ctx->fdMax = fd;
897*0Sstevel@tonic-gate 	}
898*0Sstevel@tonic-gate }
899*0Sstevel@tonic-gate #endif
900