xref: /libevent-2.1.12/kqueue.c (revision 5febb4e1)
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