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