Revert "transmission: update from 2.13 to 2.22"
[tomato.git] / release / src / router / libevent / kqueue.c
blobee740eec1d675e915fde959d93ace04a4ee5c7ab
1 /* $OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $ */
3 /*
4 * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
5 * All rights reserved.
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.
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.
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
33 #define _GNU_SOURCE 1
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
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
63 #include "event.h"
64 #include "event-internal.h"
65 #include "log.h"
66 #include "evsignal.h"
68 #define EVLIST_X_KQINKERNEL 0x1000
70 #define NEVENT 64
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;
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 *);
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 */
99 static void *
100 kq_init(struct event_base *base)
102 int i, kq;
103 struct kqop *kqueueop;
105 /* Disable kqueue when this environment variable is set */
106 if (evutil_getenv("EVENT_NOKQUEUE"))
107 return (NULL);
109 if (!(kqueueop = calloc(1, sizeof(struct kqop))))
110 return (NULL);
112 /* Initalize the kernel queue */
114 if ((kq = kqueue()) == -1) {
115 event_warn("kqueue");
116 free (kqueueop);
117 return (NULL);
120 kqueueop->kq = kq;
122 kqueueop->pid = getpid();
124 /* Initalize fields */
125 kqueueop->changes = malloc(NEVENT * sizeof(struct kevent));
126 if (kqueueop->changes == NULL) {
127 free (kqueueop);
128 return (NULL);
130 kqueueop->events = malloc(NEVENT * sizeof(struct kevent));
131 if (kqueueop->events == NULL) {
132 free (kqueueop->changes);
133 free (kqueueop);
134 return (NULL);
136 kqueueop->nevents = NEVENT;
138 /* we need to keep track of multiple events per signal */
139 for (i = 0; i < NSIG; ++i) {
140 TAILQ_INIT(&kqueueop->evsigevents[i]);
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;
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.
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);
165 return (kqueueop);
168 static int
169 kq_insert(struct kqop *kqop, struct kevent *kev)
171 int nevents = kqop->nevents;
173 if (kqop->nchanges == nevents) {
174 struct kevent *newchange;
175 struct kevent *newresult;
177 nevents *= 2;
179 newchange = realloc(kqop->changes,
180 nevents * sizeof(struct kevent));
181 if (newchange == NULL) {
182 event_warn("%s: malloc", __func__);
183 return (-1);
185 kqop->changes = newchange;
187 newresult = realloc(kqop->events,
188 nevents * sizeof(struct kevent));
191 * If we fail, we don't have to worry about freeing,
192 * the next realloc will pick it up.
194 if (newresult == NULL) {
195 event_warn("%s: malloc", __func__);
196 return (-1);
198 kqop->events = newresult;
200 kqop->nevents = nevents;
203 memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
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)" : ""));
210 return (0);
213 static void
214 kq_sighandler(int sig)
216 /* Do nothing here */
219 static int
220 kq_dispatch(struct event_base *base, void *arg, struct timeval *tv)
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;
229 if (tv != NULL) {
230 TIMEVAL_TO_TIMESPEC(tv, &ts);
231 ts_p = &ts;
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);
243 return (0);
246 event_debug(("%s: kevent reports %d", __func__, res));
248 for (i = 0; i < res; i++) {
249 int which = 0;
251 if (events[i].flags & EV_ERROR) {
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.
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);
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;
280 if (!which)
281 continue;
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);
289 } else {
290 ev = (struct event *)events[i].udata;
292 if (!(ev->ev_events & EV_PERSIST))
293 ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
295 event_active(ev, which, 1);
299 return (0);
303 static int
304 kq_add(void *arg, struct event *ev)
306 struct kqop *kqop = arg;
307 struct kevent kev;
309 if (ev->ev_events & EV_SIGNAL) {
310 int nsignal = EVENT_SIGNAL(ev);
312 assert(nsignal >= 0 && nsignal < NSIG);
313 if (TAILQ_EMPTY(&kqop->evsigevents[nsignal])) {
314 struct timespec timeout = { 0, 0 };
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]);
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);
328 if (_evsignal_set_handler(ev->ev_base, nsignal,
329 kq_sighandler) == -1)
330 return (-1);
333 TAILQ_INSERT_TAIL(&kqop->evsigevents[nsignal], ev,
334 ev_signal_next);
335 ev->ev_flags |= EVLIST_X_KQINKERNEL;
336 return (0);
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);
352 if (kq_insert(kqop, &kev) == -1)
353 return (-1);
355 ev->ev_flags |= EVLIST_X_KQINKERNEL;
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);
367 if (kq_insert(kqop, &kev) == -1)
368 return (-1);
370 ev->ev_flags |= EVLIST_X_KQINKERNEL;
373 return (0);
376 static int
377 kq_del(void *arg, struct event *ev)
379 struct kqop *kqop = arg;
380 struct kevent kev;
382 if (!(ev->ev_flags & EVLIST_X_KQINKERNEL))
383 return (0);
385 if (ev->ev_events & EV_SIGNAL) {
386 int nsignal = EVENT_SIGNAL(ev);
387 struct timespec timeout = { 0, 0 };
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;
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);
403 if (_evsignal_restore_handler(ev->ev_base,
404 nsignal) == -1)
405 return (-1);
408 ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
409 return (0);
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;
418 if (kq_insert(kqop, &kev) == -1)
419 return (-1);
421 ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
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;
430 if (kq_insert(kqop, &kev) == -1)
431 return (-1);
433 ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
436 return (0);
439 static void
440 kq_dealloc(struct event_base *base, void *arg)
442 struct kqop *kqop = arg;
444 evsignal_dealloc(base);
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);
453 memset(kqop, 0, sizeof(struct kqop));
454 free(kqop);