15f865858SNiels Provos /* $OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $ */
25f865858SNiels Provos
3aa6567feSNiels Provos /*
4b85b710cSNick Mathewson * Copyright 2000-2007 Niels Provos <[email protected]>
5e49e2891SNick Mathewson * Copyright 2007-2012 Niels Provos and Nick Mathewson
6aa6567feSNiels Provos *
7aa6567feSNiels Provos * Redistribution and use in source and binary forms, with or without
8aa6567feSNiels Provos * modification, are permitted provided that the following conditions
9aa6567feSNiels Provos * are met:
10aa6567feSNiels Provos * 1. Redistributions of source code must retain the above copyright
11aa6567feSNiels Provos * notice, this list of conditions and the following disclaimer.
12aa6567feSNiels Provos * 2. Redistributions in binary form must reproduce the above copyright
13aa6567feSNiels Provos * notice, this list of conditions and the following disclaimer in the
14aa6567feSNiels Provos * documentation and/or other materials provided with the distribution.
15c3f496c7SNiels Provos * 3. The name of the author may not be used to endorse or promote products
16aa6567feSNiels Provos * derived from this software without specific prior written permission.
17aa6567feSNiels Provos *
18aa6567feSNiels Provos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19aa6567feSNiels Provos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20aa6567feSNiels Provos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21aa6567feSNiels Provos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22aa6567feSNiels Provos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23aa6567feSNiels Provos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24aa6567feSNiels Provos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25aa6567feSNiels Provos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26aa6567feSNiels Provos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27aa6567feSNiels Provos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28aa6567feSNiels Provos */
29ec347b92SNick Mathewson #include "event2/event-config.h"
30c13e1859SKevin Bowling #include "evconfig-private.h"
314d48cf61SNick Mathewson
3268120d9bSNick Mathewson #ifdef EVENT__HAVE_KQUEUE
3376d4c929SRoss Lagerwall
34aa6567feSNiels Provos #include <sys/types.h>
3568120d9bSNick Mathewson #ifdef EVENT__HAVE_SYS_TIME_H
36aa6567feSNiels Provos #include <sys/time.h>
379d2401ffSNiels Provos #endif
38aa6567feSNiels Provos #include <sys/queue.h>
39aa6567feSNiels Provos #include <sys/event.h>
40e70e18e9STobias Stoeckmann #include <limits.h>
41d10f85dbSNiels Provos #include <signal.h>
42aa6567feSNiels Provos #include <stdio.h>
43aa6567feSNiels Provos #include <stdlib.h>
445f865858SNiels Provos #include <string.h>
45aa6567feSNiels Provos #include <unistd.h>
46aa6567feSNiels Provos #include <errno.h>
4768120d9bSNick Mathewson #ifdef EVENT__HAVE_INTTYPES_H
480036d79aSNiels Provos #include <inttypes.h>
490036d79aSNiels Provos #endif
50aa6567feSNiels Provos
517d821580SNick Mathewson /* Some platforms apparently define the udata field of struct kevent as
527d821580SNick Mathewson * intptr_t, whereas others define it as void*. There doesn't seem to be an
537d821580SNick Mathewson * easy way to tell them apart via autoconf, so we need to use OS macros. */
54*5febb4e1SKamil Rytarowski #if defined(__NetBSD__)
55*5febb4e1SKamil Rytarowski #define PTR_TO_UDATA(x) ((typeof(((struct kevent *)0)->udata))(x))
56*5febb4e1SKamil Rytarowski #define INT_TO_UDATA(x) ((typeof(((struct kevent *)0)->udata))(intptr_t)(x))
57*5febb4e1SKamil Rytarowski #elif defined(EVENT__HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__) && !defined(__CloudABI__)
587d821580SNick Mathewson #define PTR_TO_UDATA(x) ((intptr_t)(x))
591fd34ab4SNick Mathewson #define INT_TO_UDATA(x) ((intptr_t)(x))
600036d79aSNiels Provos #else
617d821580SNick Mathewson #define PTR_TO_UDATA(x) (x)
621fd34ab4SNick Mathewson #define INT_TO_UDATA(x) ((void*)(x))
630036d79aSNiels Provos #endif
640036d79aSNiels Provos
6588897852SNiels Provos #include "event-internal.h"
66169321c9SNick Mathewson #include "log-internal.h"
67169321c9SNick Mathewson #include "evmap-internal.h"
68b89b58b5SNick Mathewson #include "event2/thread.h"
6943a55a23STobias Stoeckmann #include "event2/util.h"
70b89b58b5SNick Mathewson #include "evthread-internal.h"
7145e5ae37SNick Mathewson #include "changelist-internal.h"
72aa6567feSNiels Provos
7353a07fe2SNick Mathewson #include "kqueue-internal.h"
7453a07fe2SNick Mathewson
75aa6567feSNiels Provos #define NEVENT 64
76aa6567feSNiels Provos
77aa6567feSNiels Provos struct kqop {
78aa6567feSNiels Provos struct kevent *changes;
796b22e74aSNick Mathewson int changes_size;
806b22e74aSNick Mathewson
81aa6567feSNiels Provos struct kevent *events;
826b22e74aSNick Mathewson int events_size;
83aa6567feSNiels Provos int kq;
8453a07fe2SNick Mathewson int notify_event_added;
8519dad166SNiels Provos pid_t pid;
863ba224dbSNiels Provos };
87aa6567feSNiels Provos
88315fde1aSNick Mathewson static void kqop_free(struct kqop *kqop);
89315fde1aSNick Mathewson
90ca42671aSNiels Provos static void *kq_init(struct event_base *);
912b7febc8SNick Mathewson static int kq_sig_add(struct event_base *, int, short, short, void *);
922b7febc8SNick Mathewson static int kq_sig_del(struct event_base *, int, short, short, void *);
9302b2b4d1SNiels Provos static int kq_dispatch(struct event_base *, struct timeval *);
9402b2b4d1SNiels Provos static void kq_dealloc(struct event_base *);
95aa6567feSNiels Provos
96e506eaf7SNiels Provos const struct eventop kqops = {
97aa6567feSNiels Provos "kqueue",
98aa6567feSNiels Provos kq_init,
998ac3c4c2SNick Mathewson event_changelist_add_,
1008ac3c4c2SNick Mathewson event_changelist_del_,
1012e8051f5SNiels Provos kq_dispatch,
10288897852SNiels Provos kq_dealloc,
10305965921SNick Mathewson 1 /* need reinit */,
10405965921SNick Mathewson EV_FEATURE_ET|EV_FEATURE_O1|EV_FEATURE_FDS,
10545e5ae37SNick Mathewson EVENT_CHANGELIST_FDINFO_SIZE
106aa6567feSNiels Provos };
107aa6567feSNiels Provos
10802b2b4d1SNiels Provos static const struct eventop kqsigops = {
10902b2b4d1SNiels Provos "kqueue_signal",
11002b2b4d1SNiels Provos NULL,
11102b2b4d1SNiels Provos kq_sig_add,
11202b2b4d1SNiels Provos kq_sig_del,
11302b2b4d1SNiels Provos NULL,
11402b2b4d1SNiels Provos NULL,
11502b2b4d1SNiels Provos 1 /* need reinit */,
116554e1493SNick Mathewson 0,
11702b2b4d1SNiels Provos 0
11802b2b4d1SNiels Provos };
11902b2b4d1SNiels Provos
120ca42671aSNiels Provos static void *
kq_init(struct event_base * base)12141b7cbc3SNiels Provos kq_init(struct event_base *base)
122aa6567feSNiels Provos {
123369aafc4SNick Mathewson int kq = -1;
124369aafc4SNick Mathewson struct kqop *kqueueop = NULL;
125aa6567feSNiels Provos
12649868b61SNick Mathewson if (!(kqueueop = mm_calloc(1, sizeof(struct kqop))))
1273ba224dbSNiels Provos return (NULL);
128aa6567feSNiels Provos
129e3fd294aSNick Mathewson /* Initialize the kernel queue */
130aa6567feSNiels Provos
131aa6567feSNiels Provos if ((kq = kqueue()) == -1) {
132fbdaf3abSNiels Provos event_warn("kqueue");
133369aafc4SNick Mathewson goto err;
134aa6567feSNiels Provos }
135aa6567feSNiels Provos
1363ba224dbSNiels Provos kqueueop->kq = kq;
137aa6567feSNiels Provos
13819dad166SNiels Provos kqueueop->pid = getpid();
13919dad166SNiels Provos
140e3fd294aSNick Mathewson /* Initialize fields */
14118a8cfacSNick Mathewson kqueueop->changes = mm_calloc(NEVENT, sizeof(struct kevent));
142369aafc4SNick Mathewson if (kqueueop->changes == NULL)
143369aafc4SNick Mathewson goto err;
14418a8cfacSNick Mathewson kqueueop->events = mm_calloc(NEVENT, sizeof(struct kevent));
145369aafc4SNick Mathewson if (kqueueop->events == NULL)
146369aafc4SNick Mathewson goto err;
1473225dfb9SNick Mathewson kqueueop->events_size = kqueueop->changes_size = NEVENT;
148aa6567feSNiels Provos
14957fafe6bSNiels Provos /* Check for Mac OS X kqueue bug. */
15056771a3eSWilliam Ahern memset(&kqueueop->changes[0], 0, sizeof kqueueop->changes[0]);
15157fafe6bSNiels Provos kqueueop->changes[0].ident = -1;
15257fafe6bSNiels Provos kqueueop->changes[0].filter = EVFILT_READ;
15357fafe6bSNiels Provos kqueueop->changes[0].flags = EV_ADD;
15457fafe6bSNiels Provos /*
15557fafe6bSNiels Provos * If kqueue works, then kevent will succeed, and it will
15657fafe6bSNiels Provos * stick an error in events[0]. If kqueue is broken, then
15757fafe6bSNiels Provos * kevent will fail.
15857fafe6bSNiels Provos */
15957fafe6bSNiels Provos if (kevent(kq,
16057fafe6bSNiels Provos kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 ||
1615e4bafbbSNick Mathewson (int)kqueueop->events[0].ident != -1 ||
162df6f99e5SMark Mentovai !(kqueueop->events[0].flags & EV_ERROR)) {
16357fafe6bSNiels Provos event_warn("%s: detected broken kqueue; not using.", __func__);
164369aafc4SNick Mathewson goto err;
16557fafe6bSNiels Provos }
16657fafe6bSNiels Provos
16702b2b4d1SNiels Provos base->evsigsel = &kqsigops;
16802b2b4d1SNiels Provos
1693ba224dbSNiels Provos return (kqueueop);
170369aafc4SNick Mathewson err:
171315fde1aSNick Mathewson if (kqueueop)
172315fde1aSNick Mathewson kqop_free(kqueueop);
173315fde1aSNick Mathewson
174369aafc4SNick Mathewson return (NULL);
175aa6567feSNiels Provos }
176aa6567feSNiels Provos
1771fd34ab4SNick Mathewson #define ADD_UDATA 0x30303
1781fd34ab4SNick Mathewson
17945e5ae37SNick Mathewson static void
kq_setup_kevent(struct kevent * out,evutil_socket_t fd,int filter,short change)18045e5ae37SNick Mathewson kq_setup_kevent(struct kevent *out, evutil_socket_t fd, int filter, short change)
18145e5ae37SNick Mathewson {
182c2c7b39dSSebastian Hahn memset(out, 0, sizeof(struct kevent));
18345e5ae37SNick Mathewson out->ident = fd;
18445e5ae37SNick Mathewson out->filter = filter;
18545e5ae37SNick Mathewson
18645e5ae37SNick Mathewson if (change & EV_CHANGE_ADD) {
18745e5ae37SNick Mathewson out->flags = EV_ADD;
1881fd34ab4SNick Mathewson /* We set a magic number here so that we can tell 'add'
1891fd34ab4SNick Mathewson * errors from 'del' errors. */
1901fd34ab4SNick Mathewson out->udata = INT_TO_UDATA(ADD_UDATA);
19145e5ae37SNick Mathewson if (change & EV_ET)
19245e5ae37SNick Mathewson out->flags |= EV_CLEAR;
19345e5ae37SNick Mathewson #ifdef NOTE_EOF
19445e5ae37SNick Mathewson /* Make it behave like select() and poll() */
19545e5ae37SNick Mathewson if (filter == EVFILT_READ)
19645e5ae37SNick Mathewson out->fflags = NOTE_EOF;
19745e5ae37SNick Mathewson #endif
19845e5ae37SNick Mathewson } else {
19945e5ae37SNick Mathewson EVUTIL_ASSERT(change & EV_CHANGE_DEL);
20045e5ae37SNick Mathewson out->flags = EV_DELETE;
20145e5ae37SNick Mathewson }
20245e5ae37SNick Mathewson }
20345e5ae37SNick Mathewson
20445e5ae37SNick Mathewson static int
kq_build_changes_list(const struct event_changelist * changelist,struct kqop * kqop)20545e5ae37SNick Mathewson kq_build_changes_list(const struct event_changelist *changelist,
20645e5ae37SNick Mathewson struct kqop *kqop)
20745e5ae37SNick Mathewson {
20845e5ae37SNick Mathewson int i;
20945e5ae37SNick Mathewson int n_changes = 0;
21045e5ae37SNick Mathewson
21145e5ae37SNick Mathewson for (i = 0; i < changelist->n_changes; ++i) {
21245e5ae37SNick Mathewson struct event_change *in_ch = &changelist->changes[i];
21345e5ae37SNick Mathewson struct kevent *out_ch;
21445e5ae37SNick Mathewson if (n_changes >= kqop->changes_size - 1) {
215e70e18e9STobias Stoeckmann int newsize;
21645e5ae37SNick Mathewson struct kevent *newchanges;
21745e5ae37SNick Mathewson
218e70e18e9STobias Stoeckmann if (kqop->changes_size > INT_MAX / 2 ||
219e70e18e9STobias Stoeckmann (size_t)kqop->changes_size * 2 > EV_SIZE_MAX /
220e70e18e9STobias Stoeckmann sizeof(struct kevent)) {
22143a55a23STobias Stoeckmann event_warnx("%s: int overflow", __func__);
22243a55a23STobias Stoeckmann return (-1);
22343a55a23STobias Stoeckmann }
22443a55a23STobias Stoeckmann
225e70e18e9STobias Stoeckmann newsize = kqop->changes_size * 2;
22645e5ae37SNick Mathewson newchanges = mm_realloc(kqop->changes,
22745e5ae37SNick Mathewson newsize * sizeof(struct kevent));
22845e5ae37SNick Mathewson if (newchanges == NULL) {
22945e5ae37SNick Mathewson event_warn("%s: realloc", __func__);
23045e5ae37SNick Mathewson return (-1);
23145e5ae37SNick Mathewson }
23245e5ae37SNick Mathewson kqop->changes = newchanges;
23345e5ae37SNick Mathewson kqop->changes_size = newsize;
23445e5ae37SNick Mathewson }
23545e5ae37SNick Mathewson if (in_ch->read_change) {
23645e5ae37SNick Mathewson out_ch = &kqop->changes[n_changes++];
23745e5ae37SNick Mathewson kq_setup_kevent(out_ch, in_ch->fd, EVFILT_READ,
23845e5ae37SNick Mathewson in_ch->read_change);
23945e5ae37SNick Mathewson }
24045e5ae37SNick Mathewson if (in_ch->write_change) {
24145e5ae37SNick Mathewson out_ch = &kqop->changes[n_changes++];
24245e5ae37SNick Mathewson kq_setup_kevent(out_ch, in_ch->fd, EVFILT_WRITE,
24345e5ae37SNick Mathewson in_ch->write_change);
24445e5ae37SNick Mathewson }
24545e5ae37SNick Mathewson }
24645e5ae37SNick Mathewson return n_changes;
24745e5ae37SNick Mathewson }
24845e5ae37SNick Mathewson
249ca42671aSNiels Provos static int
kq_grow_events(struct kqop * kqop,size_t new_size)25028317a08SNick Mathewson kq_grow_events(struct kqop *kqop, size_t new_size)
25128317a08SNick Mathewson {
25228317a08SNick Mathewson struct kevent *newresult;
25328317a08SNick Mathewson
25428317a08SNick Mathewson newresult = mm_realloc(kqop->events,
25528317a08SNick Mathewson new_size * sizeof(struct kevent));
25628317a08SNick Mathewson
25728317a08SNick Mathewson if (newresult) {
25828317a08SNick Mathewson kqop->events = newresult;
25928317a08SNick Mathewson kqop->events_size = new_size;
26028317a08SNick Mathewson return 0;
26128317a08SNick Mathewson } else {
26228317a08SNick Mathewson return -1;
26328317a08SNick Mathewson }
26428317a08SNick Mathewson }
26528317a08SNick Mathewson
26628317a08SNick Mathewson static int
kq_dispatch(struct event_base * base,struct timeval * tv)26702b2b4d1SNiels Provos kq_dispatch(struct event_base *base, struct timeval *tv)
268aa6567feSNiels Provos {
26902b2b4d1SNiels Provos struct kqop *kqop = base->evbase;
270aa6567feSNiels Provos struct kevent *events = kqop->events;
2713225dfb9SNick Mathewson struct kevent *changes;
2723ad6b47eSNiels Provos struct timespec ts, *ts_p = NULL;
27345e5ae37SNick Mathewson int i, n_changes, res;
274aa6567feSNiels Provos
2753ad6b47eSNiels Provos if (tv != NULL) {
276193c7de5SEd Schouten ts.tv_sec = tv->tv_sec;
277193c7de5SEd Schouten ts.tv_nsec = tv->tv_usec * 1000;
2783ad6b47eSNiels Provos ts_p = &ts;
2793ad6b47eSNiels Provos }
280aa6567feSNiels Provos
28145e5ae37SNick Mathewson /* Build "changes" from "base->changes" */
2823225dfb9SNick Mathewson EVUTIL_ASSERT(kqop->changes);
28345e5ae37SNick Mathewson n_changes = kq_build_changes_list(&base->changelist, kqop);
28445e5ae37SNick Mathewson if (n_changes < 0)
28545e5ae37SNick Mathewson return -1;
28645e5ae37SNick Mathewson
2878ac3c4c2SNick Mathewson event_changelist_remove_all_(&base->changelist, base);
28845e5ae37SNick Mathewson
2893225dfb9SNick Mathewson /* steal the changes array in case some broken code tries to call
2903225dfb9SNick Mathewson * dispatch twice at once. */
2913225dfb9SNick Mathewson changes = kqop->changes;
2923225dfb9SNick Mathewson kqop->changes = NULL;
2936b22e74aSNick Mathewson
29428317a08SNick Mathewson /* Make sure that 'events' is at least as long as the list of changes:
29528317a08SNick Mathewson * otherwise errors in the changes can get reported as a -1 return
29628317a08SNick Mathewson * value from kevent() rather than as EV_ERROR events in the events
29728317a08SNick Mathewson * array.
29828317a08SNick Mathewson *
29928317a08SNick Mathewson * (We could instead handle -1 return values from kevent() by
30028317a08SNick Mathewson * retrying with a smaller changes array or a larger events array,
30128317a08SNick Mathewson * but this approach seems less risky for now.)
30228317a08SNick Mathewson */
30328317a08SNick Mathewson if (kqop->events_size < n_changes) {
30428317a08SNick Mathewson int new_size = kqop->events_size;
30528317a08SNick Mathewson do {
30628317a08SNick Mathewson new_size *= 2;
30728317a08SNick Mathewson } while (new_size < n_changes);
30828317a08SNick Mathewson
30928317a08SNick Mathewson kq_grow_events(kqop, new_size);
31028317a08SNick Mathewson events = kqop->events;
31128317a08SNick Mathewson }
31228317a08SNick Mathewson
31376cd2b70SNick Mathewson EVBASE_RELEASE_LOCK(base, th_base_lock);
3146b22e74aSNick Mathewson
3153225dfb9SNick Mathewson res = kevent(kqop->kq, changes, n_changes,
3166b22e74aSNick Mathewson events, kqop->events_size, ts_p);
3176b22e74aSNick Mathewson
31876cd2b70SNick Mathewson EVBASE_ACQUIRE_LOCK(base, th_base_lock);
3196b22e74aSNick Mathewson
3203225dfb9SNick Mathewson EVUTIL_ASSERT(kqop->changes == NULL);
3213225dfb9SNick Mathewson kqop->changes = changes;
3223225dfb9SNick Mathewson
323aa6567feSNiels Provos if (res == -1) {
324aa6567feSNiels Provos if (errno != EINTR) {
325fbdaf3abSNiels Provos event_warn("kevent");
326aa6567feSNiels Provos return (-1);
327aa6567feSNiels Provos }
328aa6567feSNiels Provos
329aa6567feSNiels Provos return (0);
330aa6567feSNiels Provos }
331aa6567feSNiels Provos
332fbdaf3abSNiels Provos event_debug(("%s: kevent reports %d", __func__, res));
333aa6567feSNiels Provos
334aa6567feSNiels Provos for (i = 0; i < res; i++) {
335aa6567feSNiels Provos int which = 0;
336aa6567feSNiels Provos
337aa6567feSNiels Provos if (events[i].flags & EV_ERROR) {
3381fd34ab4SNick Mathewson switch (events[i].data) {
3391fd34ab4SNick Mathewson
3401fd34ab4SNick Mathewson /* Can occur on delete if we are not currently
3411fd34ab4SNick Mathewson * watching any events on this fd. That can
3421fd34ab4SNick Mathewson * happen when the fd was closed and another
3431fd34ab4SNick Mathewson * file was opened with that fd. */
3441fd34ab4SNick Mathewson case ENOENT:
3451fd34ab4SNick Mathewson /* Can occur for reasons not fully understood
3461fd34ab4SNick Mathewson * on FreeBSD. */
3471fd34ab4SNick Mathewson case EINVAL:
348aa6567feSNiels Provos continue;
3496fd73944SAdrian Chadd #if defined(__FreeBSD__)
3506fd73944SAdrian Chadd /*
3516fd73944SAdrian Chadd * This currently occurs if an FD is closed
3526fd73944SAdrian Chadd * before the EV_DELETE makes it out via kevent().
3536fd73944SAdrian Chadd * The FreeBSD capabilities code sees the blank
3546fd73944SAdrian Chadd * capability set and rejects the request to
3556fd73944SAdrian Chadd * modify an event.
3566fd73944SAdrian Chadd *
3576fd73944SAdrian Chadd * To be strictly correct - when an FD is closed,
3586fd73944SAdrian Chadd * all the registered events are also removed.
3596fd73944SAdrian Chadd * Queuing EV_DELETE to a closed FD is wrong.
3606fd73944SAdrian Chadd * The event(s) should just be deleted from
3616fd73944SAdrian Chadd * the pending changelist.
3626fd73944SAdrian Chadd */
3636fd73944SAdrian Chadd case ENOTCAPABLE:
3646fd73944SAdrian Chadd continue;
3656fd73944SAdrian Chadd #endif
3661fd34ab4SNick Mathewson
3675d7bfa15SNick Mathewson /* Can occur on a delete if the fd is closed. */
3681fd34ab4SNick Mathewson case EBADF:
3695d7bfa15SNick Mathewson /* XXXX On NetBSD, we can also get EBADF if we
3705d7bfa15SNick Mathewson * try to add the write side of a pipe, but
3715d7bfa15SNick Mathewson * the read side has already been closed.
3725d7bfa15SNick Mathewson * Other BSDs call this situation 'EPIPE'. It
3735d7bfa15SNick Mathewson * would be good if we had a way to report
3745d7bfa15SNick Mathewson * this situation. */
3755d7bfa15SNick Mathewson continue;
3761fd34ab4SNick Mathewson /* These two can occur on an add if the fd was one side
3771fd34ab4SNick Mathewson * of a pipe, and the other side was closed. */
3781fd34ab4SNick Mathewson case EPERM:
3791fd34ab4SNick Mathewson case EPIPE:
3801fd34ab4SNick Mathewson /* Report read events, if we're listening for
3811fd34ab4SNick Mathewson * them, so that the user can learn about any
3821fd34ab4SNick Mathewson * add errors. (If the operation was a
3831fd34ab4SNick Mathewson * delete, then udata should be cleared.) */
3841fd34ab4SNick Mathewson if (events[i].udata) {
3851fd34ab4SNick Mathewson /* The operation was an add:
3861fd34ab4SNick Mathewson * report the error as a read. */
3871fd34ab4SNick Mathewson which |= EV_READ;
3881fd34ab4SNick Mathewson break;
3891fd34ab4SNick Mathewson } else {
3901fd34ab4SNick Mathewson /* The operation was a del:
3911fd34ab4SNick Mathewson * report nothing. */
3921fd34ab4SNick Mathewson continue;
3931fd34ab4SNick Mathewson }
3941fd34ab4SNick Mathewson
3951fd34ab4SNick Mathewson /* Other errors shouldn't occur. */
3961fd34ab4SNick Mathewson default:
397d47798beSNiels Provos errno = events[i].data;
398aa6567feSNiels Provos return (-1);
399aa6567feSNiels Provos }
4001fd34ab4SNick Mathewson } else if (events[i].filter == EVFILT_READ) {
401aa6567feSNiels Provos which |= EV_READ;
402aa6567feSNiels Provos } else if (events[i].filter == EVFILT_WRITE) {
403aa6567feSNiels Provos which |= EV_WRITE;
404d10f85dbSNiels Provos } else if (events[i].filter == EVFILT_SIGNAL) {
405d10f85dbSNiels Provos which |= EV_SIGNAL;
40653a07fe2SNick Mathewson #ifdef EVFILT_USER
40753a07fe2SNick Mathewson } else if (events[i].filter == EVFILT_USER) {
40853a07fe2SNick Mathewson base->is_notify_pending = 0;
40953a07fe2SNick Mathewson #endif
4100036d79aSNiels Provos }
411aa6567feSNiels Provos
412484e594eSNiels Provos if (!which)
413484e594eSNiels Provos continue;
414484e594eSNiels Provos
415f7e61870SNiels Provos if (events[i].filter == EVFILT_SIGNAL) {
4168ac3c4c2SNick Mathewson evmap_signal_active_(base, events[i].ident, 1);
417f7e61870SNiels Provos } else {
4188ac3c4c2SNick Mathewson evmap_io_active_(base, events[i].ident, which | EV_ET);
419f7e61870SNiels Provos }
420aa6567feSNiels Provos }
421aa6567feSNiels Provos
422b89b58b5SNick Mathewson if (res == kqop->events_size) {
4236b22e74aSNick Mathewson /* We used all the events space that we have. Maybe we should
4246b22e74aSNick Mathewson make it bigger. */
42528317a08SNick Mathewson kq_grow_events(kqop, kqop->events_size * 2);
4266b22e74aSNick Mathewson }
4276b22e74aSNick Mathewson
428aa6567feSNiels Provos return (0);
429aa6567feSNiels Provos }
430aa6567feSNiels Provos
43102b2b4d1SNiels Provos static void
kqop_free(struct kqop * kqop)432315fde1aSNick Mathewson kqop_free(struct kqop *kqop)
43302b2b4d1SNiels Provos {
43402b2b4d1SNiels Provos if (kqop->changes)
43502b2b4d1SNiels Provos mm_free(kqop->changes);
43602b2b4d1SNiels Provos if (kqop->events)
43702b2b4d1SNiels Provos mm_free(kqop->events);
43802b2b4d1SNiels Provos if (kqop->kq >= 0 && kqop->pid == getpid())
43902b2b4d1SNiels Provos close(kqop->kq);
44002b2b4d1SNiels Provos memset(kqop, 0, sizeof(struct kqop));
44102b2b4d1SNiels Provos mm_free(kqop);
44202b2b4d1SNiels Provos }
44302b2b4d1SNiels Provos
444315fde1aSNick Mathewson static void
kq_dealloc(struct event_base * base)445315fde1aSNick Mathewson kq_dealloc(struct event_base *base)
446315fde1aSNick Mathewson {
447315fde1aSNick Mathewson struct kqop *kqop = base->evbase;
4488ac3c4c2SNick Mathewson evsig_dealloc_(base);
449315fde1aSNick Mathewson kqop_free(kqop);
450315fde1aSNick Mathewson }
451315fde1aSNick Mathewson
45202b2b4d1SNiels Provos /* signal handling */
45302b2b4d1SNiels Provos static int
kq_sig_add(struct event_base * base,int nsignal,short old,short events,void * p)4542b7febc8SNick Mathewson kq_sig_add(struct event_base *base, int nsignal, short old, short events, void *p)
45502b2b4d1SNiels Provos {
45602b2b4d1SNiels Provos struct kqop *kqop = base->evbase;
45702b2b4d1SNiels Provos struct kevent kev;
45802b2b4d1SNiels Provos struct timespec timeout = { 0, 0 };
4592b7febc8SNick Mathewson (void)p;
460f7e61870SNiels Provos
4612e36dbe1SNick Mathewson EVUTIL_ASSERT(nsignal >= 0 && nsignal < NSIG);
462d10f85dbSNiels Provos
463d10f85dbSNiels Provos memset(&kev, 0, sizeof(kev));
464d10f85dbSNiels Provos kev.ident = nsignal;
465d10f85dbSNiels Provos kev.filter = EVFILT_SIGNAL;
466d10f85dbSNiels Provos kev.flags = EV_ADD;
467d10f85dbSNiels Provos
468f7e61870SNiels Provos /* Be ready for the signal if it is sent any
469f7e61870SNiels Provos * time between now and the next call to
470f7e61870SNiels Provos * kq_dispatch. */
4712823cb05SNick Mathewson if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
472d10f85dbSNiels Provos return (-1);
473d10f85dbSNiels Provos
474148458e0SZack Weinberg /* We can set the handler for most signals to SIG_IGN and
475148458e0SZack Weinberg * still have them reported to us in the queue. However,
476148458e0SZack Weinberg * if the handler for SIGCHLD is SIG_IGN, the system reaps
477148458e0SZack Weinberg * zombie processes for us, and we don't get any notification.
478148458e0SZack Weinberg * This appears to be the only signal with this quirk. */
479cb9da0bfSNick Mathewson if (evsig_set_handler_(base, nsignal,
480148458e0SZack Weinberg nsignal == SIGCHLD ? SIG_DFL : SIG_IGN) == -1)
481d10f85dbSNiels Provos return (-1);
482aa6567feSNiels Provos
483aa6567feSNiels Provos return (0);
484aa6567feSNiels Provos }
485aa6567feSNiels Provos
486ca42671aSNiels Provos static int
kq_sig_del(struct event_base * base,int nsignal,short old,short events,void * p)4872b7febc8SNick Mathewson kq_sig_del(struct event_base *base, int nsignal, short old, short events, void *p)
488aa6567feSNiels Provos {
48902b2b4d1SNiels Provos struct kqop *kqop = base->evbase;
490aa6567feSNiels Provos struct kevent kev;
491aa6567feSNiels Provos
4925512be01SNiels Provos struct timespec timeout = { 0, 0 };
4932b7febc8SNick Mathewson (void)p;
494d10f85dbSNiels Provos
4952e36dbe1SNick Mathewson EVUTIL_ASSERT(nsignal >= 0 && nsignal < NSIG);
49602b2b4d1SNiels Provos
497d10f85dbSNiels Provos memset(&kev, 0, sizeof(kev));
49864c76fbeSNiels Provos kev.ident = nsignal;
499d10f85dbSNiels Provos kev.filter = EVFILT_SIGNAL;
500d10f85dbSNiels Provos kev.flags = EV_DELETE;
501d10f85dbSNiels Provos
502f7e61870SNiels Provos /* Because we insert signal events
503f7e61870SNiels Provos * immediately, we need to delete them
504f7e61870SNiels Provos * immediately, too */
5055512be01SNiels Provos if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
506d10f85dbSNiels Provos return (-1);
507d10f85dbSNiels Provos
508cb9da0bfSNick Mathewson if (evsig_restore_handler_(base, nsignal) == -1)
509d10f85dbSNiels Provos return (-1);
510aa6567feSNiels Provos
511aa6567feSNiels Provos return (0);
512aa6567feSNiels Provos }
51376d4c929SRoss Lagerwall
51453a07fe2SNick Mathewson
51553a07fe2SNick Mathewson /* OSX 10.6 and FreeBSD 8.1 add support for EVFILT_USER, which we can use
51653a07fe2SNick Mathewson * to wake up the event loop from another thread. */
51753a07fe2SNick Mathewson
51853a07fe2SNick Mathewson /* Magic number we use for our filter ID. */
51953a07fe2SNick Mathewson #define NOTIFY_IDENT 42
52053a07fe2SNick Mathewson
52153a07fe2SNick Mathewson int
event_kq_add_notify_event_(struct event_base * base)52253a07fe2SNick Mathewson event_kq_add_notify_event_(struct event_base *base)
52353a07fe2SNick Mathewson {
52453a07fe2SNick Mathewson struct kqop *kqop = base->evbase;
52553a07fe2SNick Mathewson #if defined(EVFILT_USER) && defined(NOTE_TRIGGER)
52653a07fe2SNick Mathewson struct kevent kev;
52753a07fe2SNick Mathewson struct timespec timeout = { 0, 0 };
52853a07fe2SNick Mathewson #endif
52953a07fe2SNick Mathewson
53053a07fe2SNick Mathewson if (kqop->notify_event_added)
53153a07fe2SNick Mathewson return 0;
53253a07fe2SNick Mathewson
53353a07fe2SNick Mathewson #if defined(EVFILT_USER) && defined(NOTE_TRIGGER)
53453a07fe2SNick Mathewson memset(&kev, 0, sizeof(kev));
53553a07fe2SNick Mathewson kev.ident = NOTIFY_IDENT;
53653a07fe2SNick Mathewson kev.filter = EVFILT_USER;
53753a07fe2SNick Mathewson kev.flags = EV_ADD | EV_CLEAR;
53853a07fe2SNick Mathewson
53953a07fe2SNick Mathewson if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1) {
54053a07fe2SNick Mathewson event_warn("kevent: adding EVFILT_USER event");
54153a07fe2SNick Mathewson return -1;
54253a07fe2SNick Mathewson }
54353a07fe2SNick Mathewson
54453a07fe2SNick Mathewson kqop->notify_event_added = 1;
54553a07fe2SNick Mathewson
54653a07fe2SNick Mathewson return 0;
54753a07fe2SNick Mathewson #else
54853a07fe2SNick Mathewson return -1;
54953a07fe2SNick Mathewson #endif
55053a07fe2SNick Mathewson }
55153a07fe2SNick Mathewson
55253a07fe2SNick Mathewson int
event_kq_notify_base_(struct event_base * base)55353a07fe2SNick Mathewson event_kq_notify_base_(struct event_base *base)
55453a07fe2SNick Mathewson {
55553a07fe2SNick Mathewson struct kqop *kqop = base->evbase;
55653a07fe2SNick Mathewson #if defined(EVFILT_USER) && defined(NOTE_TRIGGER)
55753a07fe2SNick Mathewson struct kevent kev;
55853a07fe2SNick Mathewson struct timespec timeout = { 0, 0 };
55953a07fe2SNick Mathewson #endif
56053a07fe2SNick Mathewson if (! kqop->notify_event_added)
56153a07fe2SNick Mathewson return -1;
56253a07fe2SNick Mathewson
56353a07fe2SNick Mathewson #if defined(EVFILT_USER) && defined(NOTE_TRIGGER)
56453a07fe2SNick Mathewson memset(&kev, 0, sizeof(kev));
56553a07fe2SNick Mathewson kev.ident = NOTIFY_IDENT;
56653a07fe2SNick Mathewson kev.filter = EVFILT_USER;
56753a07fe2SNick Mathewson kev.fflags = NOTE_TRIGGER;
56853a07fe2SNick Mathewson
56953a07fe2SNick Mathewson if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1) {
57053a07fe2SNick Mathewson event_warn("kevent: triggering EVFILT_USER event");
57153a07fe2SNick Mathewson return -1;
57253a07fe2SNick Mathewson }
57353a07fe2SNick Mathewson
57453a07fe2SNick Mathewson return 0;
57553a07fe2SNick Mathewson #else
57653a07fe2SNick Mathewson return -1;
57753a07fe2SNick Mathewson #endif
57853a07fe2SNick Mathewson }
57953a07fe2SNick Mathewson
58068120d9bSNick Mathewson #endif /* EVENT__HAVE_KQUEUE */
581