1 /* $OpenBSD: kqueue.c,v 1.28 2012/02/08 09:01:00 nicm 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 __RCSID("$MirOS: src/lib/libevent/kqueue.c,v 1.7 2012/10/19 19:58:18 tg Exp $");
69
70 #define EVLIST_X_KQINKERNEL 0x1000
71
72 #define NEVENT 64
73
74 struct kqop {
75 struct kevent *changes;
76 int nchanges;
77 struct kevent *events;
78 struct event_list evsigevents[NSIG];
79 int nevents;
80 int kq;
81 pid_t pid;
82 };
83
84 static void *kq_init (struct event_base *);
85 static int kq_add (void *, struct event *);
86 static int kq_del (void *, struct event *);
87 static int kq_dispatch (struct event_base *, void *, struct timeval *);
88 static int kq_insert (struct kqop *, struct kevent *);
89 static void kq_dealloc (struct event_base *, void *);
90
91 const struct eventop kqops = {
92 "kqueue",
93 kq_init,
94 kq_add,
95 kq_del,
96 kq_dispatch,
97 kq_dealloc,
98 1 /* need reinit */
99 };
100
101 static void *
kq_init(struct event_base * base __unused)102 kq_init(struct event_base *base __unused)
103 {
104 int i, kq;
105 struct kqop *kqueueop;
106
107 /* Disable kqueue when this environment variable is set */
108 if (evutil_getenv("EVENT_NOKQUEUE"))
109 return (NULL);
110
111 if (!(kqueueop = calloc(1, sizeof(struct kqop))))
112 return (NULL);
113
114 /* Initalize the kernel queue */
115
116 if ((kq = kqueue()) == -1) {
117 event_warn("kqueue");
118 free (kqueueop);
119 return (NULL);
120 }
121
122 kqueueop->kq = kq;
123
124 kqueueop->pid = getpid();
125
126 /* Initalize fields */
127 kqueueop->changes = calloc(NEVENT, sizeof(struct kevent));
128 if (kqueueop->changes == NULL) {
129 free (kqueueop);
130 return (NULL);
131 }
132 kqueueop->events = calloc(NEVENT, sizeof(struct kevent));
133 if (kqueueop->events == NULL) {
134 free (kqueueop->changes);
135 free (kqueueop);
136 return (NULL);
137 }
138 kqueueop->nevents = NEVENT;
139
140 /* we need to keep track of multiple events per signal */
141 for (i = 0; i < NSIG; ++i) {
142 TAILQ_INIT(&kqueueop->evsigevents[i]);
143 }
144
145 /* Check for Mac OS X kqueue bug. */
146 kqueueop->changes[0].ident = -1;
147 kqueueop->changes[0].filter = EVFILT_READ;
148 kqueueop->changes[0].flags = EV_ADD;
149 /*
150 * If kqueue works, then kevent will succeed, and it will
151 * stick an error in events[0]. If kqueue is broken, then
152 * kevent will fail.
153 */
154 if (kevent(kq,
155 kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 ||
156 kqueueop->events[0].ident != (u_int)-1 ||
157 kqueueop->events[0].flags != EV_ERROR) {
158 event_warn("%s: detected broken kqueue; not using.", __func__);
159 free(kqueueop->changes);
160 free(kqueueop->events);
161 free(kqueueop);
162 close(kq);
163 return (NULL);
164 }
165
166 return (kqueueop);
167 }
168
169 static int
kq_insert(struct kqop * kqop,struct kevent * kev)170 kq_insert(struct kqop *kqop, struct kevent *kev)
171 {
172 int nevents = kqop->nevents;
173
174 if (kqop->nchanges == nevents) {
175 struct kevent *newchange;
176 struct kevent *newresult;
177
178 nevents *= 2;
179
180 newchange = realloc(kqop->changes,
181 nevents * sizeof(struct kevent));
182 if (newchange == NULL) {
183 event_warn("%s: malloc", __func__);
184 return (-1);
185 }
186 kqop->changes = newchange;
187
188 newresult = realloc(kqop->events,
189 nevents * sizeof(struct kevent));
190
191 /*
192 * If we fail, we don't have to worry about freeing,
193 * the next realloc will pick it up.
194 */
195 if (newresult == NULL) {
196 event_warn("%s: malloc", __func__);
197 return (-1);
198 }
199 kqop->events = newresult;
200
201 kqop->nevents = nevents;
202 }
203
204 memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
205
206 event_debug(("%s: fd %d %s%s",
207 __func__, (int)kev->ident,
208 kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
209 kev->flags == EV_DELETE ? " (del)" : ""));
210
211 return (0);
212 }
213
214 static void
kq_sighandler(int sig __unused)215 kq_sighandler(int sig __unused)
216 {
217 /* Do nothing here */
218 }
219
220 static int
kq_dispatch(struct event_base * base __unused,void * arg,struct timeval * tv)221 kq_dispatch(struct event_base *base __unused, void *arg, struct timeval *tv)
222 {
223 struct kqop *kqop = arg;
224 struct kevent *changes = kqop->changes;
225 struct kevent *events = kqop->events;
226 struct event *ev;
227 struct timespec ts, *ts_p = NULL;
228 int i, res;
229
230 if (tv != NULL) {
231 TIMEVAL_TO_TIMESPEC(tv, &ts);
232 ts_p = &ts;
233 }
234
235 res = kevent(kqop->kq, changes, kqop->nchanges,
236 events, kqop->nevents, ts_p);
237 kqop->nchanges = 0;
238 if (res == -1) {
239 if (errno != EINTR) {
240 event_warn("kevent");
241 return (-1);
242 }
243
244 return (0);
245 }
246
247 event_debug(("%s: kevent reports %d", __func__, res));
248
249 for (i = 0; i < res; i++) {
250 int which = 0;
251
252 if (events[i].flags & EV_ERROR) {
253 switch (events[i].data) {
254
255 /* Can occur on delete if we are not currently
256 * watching any events on this fd. That can
257 * happen when the fd was closed and another
258 * file was opened with that fd. */
259 case ENOENT:
260 /* Can occur for reasons not fully understood
261 * on FreeBSD. */
262 case EINVAL:
263 continue;
264 /* Can occur on a delete if the fd is closed. Can
265 * occur on an add if the fd was one side of a pipe,
266 * and the other side was closed. */
267 case EBADF:
268 continue;
269 /* These two can occur on an add if the fd was one side
270 * of a pipe, and the other side was closed. */
271 case EPERM:
272 case EPIPE:
273 /* Report read events, if we're listening for
274 * them, so that the user can learn about any
275 * add errors. (If the operation was a
276 * delete, then udata should be cleared.) */
277 if (events[i].udata) {
278 /* The operation was an add:
279 * report the error as a read. */
280 which |= EV_READ;
281 break;
282 } else {
283 /* The operation was a del:
284 * report nothing. */
285 continue;
286 }
287
288 /* Other errors shouldn't occur. */
289 default:
290 errno = events[i].data;
291 return (-1);
292 }
293 } else if (events[i].filter == EVFILT_READ) {
294 which |= EV_READ;
295 } else if (events[i].filter == EVFILT_WRITE) {
296 which |= EV_WRITE;
297 } else if (events[i].filter == EVFILT_SIGNAL) {
298 which |= EV_SIGNAL;
299 }
300
301 if (!which)
302 continue;
303
304 if (events[i].filter == EVFILT_SIGNAL) {
305 struct event_list *head =
306 (struct event_list *)events[i].udata;
307 TAILQ_FOREACH(ev, head, ev_signal_next) {
308 event_active(ev, which, events[i].data);
309 }
310 } else {
311 ev = (struct event *)events[i].udata;
312
313 if (!(ev->ev_events & EV_PERSIST))
314 ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
315
316 event_active(ev, which, 1);
317 }
318 }
319
320 return (0);
321 }
322
323
324 static int
kq_add(void * arg,struct event * ev)325 kq_add(void *arg, struct event *ev)
326 {
327 struct kqop *kqop = arg;
328 struct kevent kev;
329
330 if (ev->ev_events & EV_SIGNAL) {
331 int nsignal = EVENT_SIGNAL(ev);
332
333 assert(nsignal >= 0 && nsignal < NSIG);
334 if (TAILQ_EMPTY(&kqop->evsigevents[nsignal])) {
335 struct timespec timeout = { 0, 0 };
336
337 memset(&kev, 0, sizeof(kev));
338 kev.ident = nsignal;
339 kev.filter = EVFILT_SIGNAL;
340 kev.flags = EV_ADD;
341 kev.udata = PTR_TO_UDATA(&kqop->evsigevents[nsignal]);
342
343 /* Be ready for the signal if it is sent any
344 * time between now and the next call to
345 * kq_dispatch. */
346 if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
347 return (-1);
348
349 if (_evsignal_set_handler(ev->ev_base, nsignal,
350 kq_sighandler) == -1)
351 return (-1);
352 }
353
354 TAILQ_INSERT_TAIL(&kqop->evsigevents[nsignal], ev,
355 ev_signal_next);
356 ev->ev_flags |= EVLIST_X_KQINKERNEL;
357 return (0);
358 }
359
360 if (ev->ev_events & EV_READ) {
361 memset(&kev, 0, sizeof(kev));
362 kev.ident = ev->ev_fd;
363 kev.filter = EVFILT_READ;
364 #ifdef NOTE_EOF
365 /* Make it behave like select() and poll() */
366 kev.fflags = NOTE_EOF;
367 #endif
368 kev.flags = EV_ADD;
369 if (!(ev->ev_events & EV_PERSIST))
370 kev.flags |= EV_ONESHOT;
371 kev.udata = PTR_TO_UDATA(ev);
372
373 if (kq_insert(kqop, &kev) == -1)
374 return (-1);
375
376 ev->ev_flags |= EVLIST_X_KQINKERNEL;
377 }
378
379 if (ev->ev_events & EV_WRITE) {
380 memset(&kev, 0, sizeof(kev));
381 kev.ident = ev->ev_fd;
382 kev.filter = EVFILT_WRITE;
383 kev.flags = EV_ADD;
384 if (!(ev->ev_events & EV_PERSIST))
385 kev.flags |= EV_ONESHOT;
386 kev.udata = PTR_TO_UDATA(ev);
387
388 if (kq_insert(kqop, &kev) == -1)
389 return (-1);
390
391 ev->ev_flags |= EVLIST_X_KQINKERNEL;
392 }
393
394 return (0);
395 }
396
397 static int
kq_del(void * arg,struct event * ev)398 kq_del(void *arg, struct event *ev)
399 {
400 struct kqop *kqop = arg;
401 struct kevent kev;
402
403 if (!(ev->ev_flags & EVLIST_X_KQINKERNEL))
404 return (0);
405
406 if (ev->ev_events & EV_SIGNAL) {
407 int nsignal = EVENT_SIGNAL(ev);
408 struct timespec timeout = { 0, 0 };
409
410 assert(nsignal >= 0 && nsignal < NSIG);
411 TAILQ_REMOVE(&kqop->evsigevents[nsignal], ev, ev_signal_next);
412 if (TAILQ_EMPTY(&kqop->evsigevents[nsignal])) {
413 memset(&kev, 0, sizeof(kev));
414 kev.ident = nsignal;
415 kev.filter = EVFILT_SIGNAL;
416 kev.flags = EV_DELETE;
417
418 /* Because we insert signal events
419 * immediately, we need to delete them
420 * immediately, too */
421 if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
422 return (-1);
423
424 if (_evsignal_restore_handler(ev->ev_base,
425 nsignal) == -1)
426 return (-1);
427 }
428
429 ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
430 return (0);
431 }
432
433 if (ev->ev_events & EV_READ) {
434 memset(&kev, 0, sizeof(kev));
435 kev.ident = ev->ev_fd;
436 kev.filter = EVFILT_READ;
437 kev.flags = EV_DELETE;
438
439 if (kq_insert(kqop, &kev) == -1)
440 return (-1);
441
442 ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
443 }
444
445 if (ev->ev_events & EV_WRITE) {
446 memset(&kev, 0, sizeof(kev));
447 kev.ident = ev->ev_fd;
448 kev.filter = EVFILT_WRITE;
449 kev.flags = EV_DELETE;
450
451 if (kq_insert(kqop, &kev) == -1)
452 return (-1);
453
454 ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
455 }
456
457 return (0);
458 }
459
460 static void
kq_dealloc(struct event_base * base,void * arg)461 kq_dealloc(struct event_base *base, void *arg)
462 {
463 struct kqop *kqop = arg;
464
465 evsignal_dealloc(base);
466
467 if (kqop->changes)
468 free(kqop->changes);
469 if (kqop->events)
470 free(kqop->events);
471 if (kqop->kq >= 0 && kqop->pid == getpid())
472 close(kqop->kq);
473
474 memset(kqop, 0, sizeof(struct kqop));
475 free(kqop);
476 }
477