Annotation of embedaddon/libevent/kqueue.c, revision 1.1.1.1
1.1 misho 1: /* $OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $ */
2:
3: /*
4: * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. The name of the author may not be used to endorse or promote products
16: * derived from this software without specific prior written permission.
17: *
18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28: */
29: #ifdef HAVE_CONFIG_H
30: #include "config.h"
31: #endif
32:
33: #define _GNU_SOURCE 1
34:
35: #include <sys/types.h>
36: #ifdef HAVE_SYS_TIME_H
37: #include <sys/time.h>
38: #else
39: #include <sys/_libevent_time.h>
40: #endif
41: #include <sys/queue.h>
42: #include <sys/event.h>
43: #include <signal.h>
44: #include <stdio.h>
45: #include <stdlib.h>
46: #include <string.h>
47: #include <unistd.h>
48: #include <errno.h>
49: #include <assert.h>
50: #ifdef HAVE_INTTYPES_H
51: #include <inttypes.h>
52: #endif
53:
54: /* Some platforms apparently define the udata field of struct kevent as
55: * intptr_t, whereas others define it as void*. There doesn't seem to be an
56: * easy way to tell them apart via autoconf, so we need to use OS macros. */
57: #if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__)
58: #define PTR_TO_UDATA(x) ((intptr_t)(x))
59: #else
60: #define PTR_TO_UDATA(x) (x)
61: #endif
62:
63: #include "event.h"
64: #include "event-internal.h"
65: #include "log.h"
66: #include "evsignal.h"
67:
68: #define EVLIST_X_KQINKERNEL 0x1000
69:
70: #define NEVENT 64
71:
72: struct kqop {
73: struct kevent *changes;
74: int nchanges;
75: struct kevent *events;
76: struct event_list evsigevents[NSIG];
77: int nevents;
78: int kq;
79: pid_t pid;
80: };
81:
82: static void *kq_init (struct event_base *);
83: static int kq_add (void *, struct event *);
84: static int kq_del (void *, struct event *);
85: static int kq_dispatch (struct event_base *, void *, struct timeval *);
86: static int kq_insert (struct kqop *, struct kevent *);
87: static void kq_dealloc (struct event_base *, void *);
88:
89: const struct eventop kqops = {
90: "kqueue",
91: kq_init,
92: kq_add,
93: kq_del,
94: kq_dispatch,
95: kq_dealloc,
96: 1 /* need reinit */
97: };
98:
99: static void *
100: kq_init(struct event_base *base)
101: {
102: int i, kq;
103: struct kqop *kqueueop;
104:
105: /* Disable kqueue when this environment variable is set */
106: if (evutil_getenv("EVENT_NOKQUEUE"))
107: return (NULL);
108:
109: if (!(kqueueop = calloc(1, sizeof(struct kqop))))
110: return (NULL);
111:
112: /* Initalize the kernel queue */
113:
114: if ((kq = kqueue()) == -1) {
115: event_warn("kqueue");
116: free (kqueueop);
117: return (NULL);
118: }
119:
120: kqueueop->kq = kq;
121:
122: kqueueop->pid = getpid();
123:
124: /* Initalize fields */
125: kqueueop->changes = malloc(NEVENT * sizeof(struct kevent));
126: if (kqueueop->changes == NULL) {
127: free (kqueueop);
128: return (NULL);
129: }
130: kqueueop->events = malloc(NEVENT * sizeof(struct kevent));
131: if (kqueueop->events == NULL) {
132: free (kqueueop->changes);
133: free (kqueueop);
134: return (NULL);
135: }
136: kqueueop->nevents = NEVENT;
137:
138: /* we need to keep track of multiple events per signal */
139: for (i = 0; i < NSIG; ++i) {
140: TAILQ_INIT(&kqueueop->evsigevents[i]);
141: }
142:
143: /* Check for Mac OS X kqueue bug. */
144: memset(&kqueueop->changes[0], 0, sizeof kqueueop->changes[0]);
145: kqueueop->changes[0].ident = -1;
146: kqueueop->changes[0].filter = EVFILT_READ;
147: kqueueop->changes[0].flags = EV_ADD;
148: /*
149: * If kqueue works, then kevent will succeed, and it will
150: * stick an error in events[0]. If kqueue is broken, then
151: * kevent will fail.
152: */
153: if (kevent(kq,
154: kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 ||
155: kqueueop->events[0].ident != -1 ||
156: kqueueop->events[0].flags != EV_ERROR) {
157: event_warn("%s: detected broken kqueue; not using.", __func__);
158: free(kqueueop->changes);
159: free(kqueueop->events);
160: free(kqueueop);
161: close(kq);
162: return (NULL);
163: }
164:
165: return (kqueueop);
166: }
167:
168: static int
169: kq_insert(struct kqop *kqop, struct kevent *kev)
170: {
171: int nevents = kqop->nevents;
172:
173: if (kqop->nchanges == nevents) {
174: struct kevent *newchange;
175: struct kevent *newresult;
176:
177: nevents *= 2;
178:
179: newchange = realloc(kqop->changes,
180: nevents * sizeof(struct kevent));
181: if (newchange == NULL) {
182: event_warn("%s: malloc", __func__);
183: return (-1);
184: }
185: kqop->changes = newchange;
186:
187: newresult = realloc(kqop->events,
188: nevents * sizeof(struct kevent));
189:
190: /*
191: * If we fail, we don't have to worry about freeing,
192: * the next realloc will pick it up.
193: */
194: if (newresult == NULL) {
195: event_warn("%s: malloc", __func__);
196: return (-1);
197: }
198: kqop->events = newresult;
199:
200: kqop->nevents = nevents;
201: }
202:
203: memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
204:
205: event_debug(("%s: fd %d %s%s",
206: __func__, (int)kev->ident,
207: kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
208: kev->flags == EV_DELETE ? " (del)" : ""));
209:
210: return (0);
211: }
212:
213: static void
214: kq_sighandler(int sig)
215: {
216: /* Do nothing here */
217: }
218:
219: static int
220: kq_dispatch(struct event_base *base, void *arg, struct timeval *tv)
221: {
222: struct kqop *kqop = arg;
223: struct kevent *changes = kqop->changes;
224: struct kevent *events = kqop->events;
225: struct event *ev;
226: struct timespec ts, *ts_p = NULL;
227: int i, res;
228:
229: if (tv != NULL) {
230: TIMEVAL_TO_TIMESPEC(tv, &ts);
231: ts_p = &ts;
232: }
233:
234: res = kevent(kqop->kq, changes, kqop->nchanges,
235: events, kqop->nevents, ts_p);
236: kqop->nchanges = 0;
237: if (res == -1) {
238: if (errno != EINTR) {
239: event_warn("kevent");
240: return (-1);
241: }
242:
243: return (0);
244: }
245:
246: event_debug(("%s: kevent reports %d", __func__, res));
247:
248: for (i = 0; i < res; i++) {
249: int which = 0;
250:
251: if (events[i].flags & EV_ERROR) {
252: /*
253: * Error messages that can happen, when a delete fails.
254: * EBADF happens when the file discriptor has been
255: * closed,
256: * ENOENT when the file discriptor was closed and
257: * then reopened.
258: * EINVAL for some reasons not understood; EINVAL
259: * should not be returned ever; but FreeBSD does :-\
260: * An error is also indicated when a callback deletes
261: * an event we are still processing. In that case
262: * the data field is set to ENOENT.
263: */
264: if (events[i].data == EBADF ||
265: events[i].data == EINVAL ||
266: events[i].data == ENOENT)
267: continue;
268: errno = events[i].data;
269: return (-1);
270: }
271:
272: if (events[i].filter == EVFILT_READ) {
273: which |= EV_READ;
274: } else if (events[i].filter == EVFILT_WRITE) {
275: which |= EV_WRITE;
276: } else if (events[i].filter == EVFILT_SIGNAL) {
277: which |= EV_SIGNAL;
278: }
279:
280: if (!which)
281: continue;
282:
283: if (events[i].filter == EVFILT_SIGNAL) {
284: struct event_list *head =
285: (struct event_list *)events[i].udata;
286: TAILQ_FOREACH(ev, head, ev_signal_next) {
287: event_active(ev, which, events[i].data);
288: }
289: } else {
290: ev = (struct event *)events[i].udata;
291:
292: if (!(ev->ev_events & EV_PERSIST))
293: ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
294:
295: event_active(ev, which, 1);
296: }
297: }
298:
299: return (0);
300: }
301:
302:
303: static int
304: kq_add(void *arg, struct event *ev)
305: {
306: struct kqop *kqop = arg;
307: struct kevent kev;
308:
309: if (ev->ev_events & EV_SIGNAL) {
310: int nsignal = EVENT_SIGNAL(ev);
311:
312: assert(nsignal >= 0 && nsignal < NSIG);
313: if (TAILQ_EMPTY(&kqop->evsigevents[nsignal])) {
314: struct timespec timeout = { 0, 0 };
315:
316: memset(&kev, 0, sizeof(kev));
317: kev.ident = nsignal;
318: kev.filter = EVFILT_SIGNAL;
319: kev.flags = EV_ADD;
320: kev.udata = PTR_TO_UDATA(&kqop->evsigevents[nsignal]);
321:
322: /* Be ready for the signal if it is sent any
323: * time between now and the next call to
324: * kq_dispatch. */
325: if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
326: return (-1);
327:
328: if (_evsignal_set_handler(ev->ev_base, nsignal,
329: kq_sighandler) == -1)
330: return (-1);
331: }
332:
333: TAILQ_INSERT_TAIL(&kqop->evsigevents[nsignal], ev,
334: ev_signal_next);
335: ev->ev_flags |= EVLIST_X_KQINKERNEL;
336: return (0);
337: }
338:
339: if (ev->ev_events & EV_READ) {
340: memset(&kev, 0, sizeof(kev));
341: kev.ident = ev->ev_fd;
342: kev.filter = EVFILT_READ;
343: #ifdef NOTE_EOF
344: /* Make it behave like select() and poll() */
345: kev.fflags = NOTE_EOF;
346: #endif
347: kev.flags = EV_ADD;
348: if (!(ev->ev_events & EV_PERSIST))
349: kev.flags |= EV_ONESHOT;
350: kev.udata = PTR_TO_UDATA(ev);
351:
352: if (kq_insert(kqop, &kev) == -1)
353: return (-1);
354:
355: ev->ev_flags |= EVLIST_X_KQINKERNEL;
356: }
357:
358: if (ev->ev_events & EV_WRITE) {
359: memset(&kev, 0, sizeof(kev));
360: kev.ident = ev->ev_fd;
361: kev.filter = EVFILT_WRITE;
362: kev.flags = EV_ADD;
363: if (!(ev->ev_events & EV_PERSIST))
364: kev.flags |= EV_ONESHOT;
365: kev.udata = PTR_TO_UDATA(ev);
366:
367: if (kq_insert(kqop, &kev) == -1)
368: return (-1);
369:
370: ev->ev_flags |= EVLIST_X_KQINKERNEL;
371: }
372:
373: return (0);
374: }
375:
376: static int
377: kq_del(void *arg, struct event *ev)
378: {
379: struct kqop *kqop = arg;
380: struct kevent kev;
381:
382: if (!(ev->ev_flags & EVLIST_X_KQINKERNEL))
383: return (0);
384:
385: if (ev->ev_events & EV_SIGNAL) {
386: int nsignal = EVENT_SIGNAL(ev);
387: struct timespec timeout = { 0, 0 };
388:
389: assert(nsignal >= 0 && nsignal < NSIG);
390: TAILQ_REMOVE(&kqop->evsigevents[nsignal], ev, ev_signal_next);
391: if (TAILQ_EMPTY(&kqop->evsigevents[nsignal])) {
392: memset(&kev, 0, sizeof(kev));
393: kev.ident = nsignal;
394: kev.filter = EVFILT_SIGNAL;
395: kev.flags = EV_DELETE;
396:
397: /* Because we insert signal events
398: * immediately, we need to delete them
399: * immediately, too */
400: if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
401: return (-1);
402:
403: if (_evsignal_restore_handler(ev->ev_base,
404: nsignal) == -1)
405: return (-1);
406: }
407:
408: ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
409: return (0);
410: }
411:
412: if (ev->ev_events & EV_READ) {
413: memset(&kev, 0, sizeof(kev));
414: kev.ident = ev->ev_fd;
415: kev.filter = EVFILT_READ;
416: kev.flags = EV_DELETE;
417:
418: if (kq_insert(kqop, &kev) == -1)
419: return (-1);
420:
421: ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
422: }
423:
424: if (ev->ev_events & EV_WRITE) {
425: memset(&kev, 0, sizeof(kev));
426: kev.ident = ev->ev_fd;
427: kev.filter = EVFILT_WRITE;
428: kev.flags = EV_DELETE;
429:
430: if (kq_insert(kqop, &kev) == -1)
431: return (-1);
432:
433: ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
434: }
435:
436: return (0);
437: }
438:
439: static void
440: kq_dealloc(struct event_base *base, void *arg)
441: {
442: struct kqop *kqop = arg;
443:
444: evsignal_dealloc(base);
445:
446: if (kqop->changes)
447: free(kqop->changes);
448: if (kqop->events)
449: free(kqop->events);
450: if (kqop->kq >= 0 && kqop->pid == getpid())
451: close(kqop->kq);
452:
453: memset(kqop, 0, sizeof(struct kqop));
454: free(kqop);
455: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>