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