1290001Sglebius/*	$OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $	*/
2290001Sglebius
3290001Sglebius/*
4290001Sglebius * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
5290001Sglebius * Copyright 2007-2012 Niels Provos and Nick Mathewson
6290001Sglebius *
7290001Sglebius * Redistribution and use in source and binary forms, with or without
8290001Sglebius * modification, are permitted provided that the following conditions
9290001Sglebius * are met:
10290001Sglebius * 1. Redistributions of source code must retain the above copyright
11290001Sglebius *    notice, this list of conditions and the following disclaimer.
12290001Sglebius * 2. Redistributions in binary form must reproduce the above copyright
13290001Sglebius *    notice, this list of conditions and the following disclaimer in the
14290001Sglebius *    documentation and/or other materials provided with the distribution.
15290001Sglebius * 3. The name of the author may not be used to endorse or promote products
16290001Sglebius *    derived from this software without specific prior written permission.
17290001Sglebius *
18290001Sglebius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19290001Sglebius * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20290001Sglebius * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21290001Sglebius * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22290001Sglebius * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23290001Sglebius * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24290001Sglebius * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25290001Sglebius * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26290001Sglebius * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27290001Sglebius * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28290001Sglebius */
29290001Sglebius#include "event2/event-config.h"
30290001Sglebius#include "evconfig-private.h"
31290001Sglebius
32290001Sglebius#ifdef EVENT__HAVE_KQUEUE
33290001Sglebius
34290001Sglebius#include <sys/types.h>
35290001Sglebius#ifdef EVENT__HAVE_SYS_TIME_H
36290001Sglebius#include <sys/time.h>
37290001Sglebius#endif
38290001Sglebius#include <sys/queue.h>
39290001Sglebius#include <sys/event.h>
40290001Sglebius#include <signal.h>
41290001Sglebius#include <stdio.h>
42290001Sglebius#include <stdlib.h>
43290001Sglebius#include <string.h>
44290001Sglebius#include <unistd.h>
45290001Sglebius#include <errno.h>
46290001Sglebius#ifdef EVENT__HAVE_INTTYPES_H
47290001Sglebius#include <inttypes.h>
48290001Sglebius#endif
49290001Sglebius
50290001Sglebius/* Some platforms apparently define the udata field of struct kevent as
51290001Sglebius * intptr_t, whereas others define it as void*.  There doesn't seem to be an
52290001Sglebius * easy way to tell them apart via autoconf, so we need to use OS macros. */
53290001Sglebius#if defined(EVENT__HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__)
54290001Sglebius#define PTR_TO_UDATA(x)	((intptr_t)(x))
55290001Sglebius#define INT_TO_UDATA(x) ((intptr_t)(x))
56290001Sglebius#else
57290001Sglebius#define PTR_TO_UDATA(x)	(x)
58290001Sglebius#define INT_TO_UDATA(x) ((void*)(x))
59290001Sglebius#endif
60290001Sglebius
61290001Sglebius#include "event-internal.h"
62290001Sglebius#include "log-internal.h"
63290001Sglebius#include "evmap-internal.h"
64290001Sglebius#include "event2/thread.h"
65290001Sglebius#include "evthread-internal.h"
66290001Sglebius#include "changelist-internal.h"
67290001Sglebius
68290001Sglebius#include "kqueue-internal.h"
69290001Sglebius
70290001Sglebius#define NEVENT		64
71290001Sglebius
72290001Sglebiusstruct kqop {
73290001Sglebius	struct kevent *changes;
74290001Sglebius	int changes_size;
75290001Sglebius
76290001Sglebius	struct kevent *events;
77290001Sglebius	int events_size;
78290001Sglebius	int kq;
79290001Sglebius	int notify_event_added;
80290001Sglebius	pid_t pid;
81290001Sglebius};
82290001Sglebius
83290001Sglebiusstatic void kqop_free(struct kqop *kqop);
84290001Sglebius
85290001Sglebiusstatic void *kq_init(struct event_base *);
86290001Sglebiusstatic int kq_sig_add(struct event_base *, int, short, short, void *);
87290001Sglebiusstatic int kq_sig_del(struct event_base *, int, short, short, void *);
88290001Sglebiusstatic int kq_dispatch(struct event_base *, struct timeval *);
89290001Sglebiusstatic void kq_dealloc(struct event_base *);
90290001Sglebius
91290001Sglebiusconst struct eventop kqops = {
92290001Sglebius	"kqueue",
93290001Sglebius	kq_init,
94290001Sglebius	event_changelist_add_,
95290001Sglebius	event_changelist_del_,
96290001Sglebius	kq_dispatch,
97290001Sglebius	kq_dealloc,
98290001Sglebius	1 /* need reinit */,
99290001Sglebius    EV_FEATURE_ET|EV_FEATURE_O1|EV_FEATURE_FDS,
100290001Sglebius	EVENT_CHANGELIST_FDINFO_SIZE
101290001Sglebius};
102290001Sglebius
103290001Sglebiusstatic const struct eventop kqsigops = {
104290001Sglebius	"kqueue_signal",
105290001Sglebius	NULL,
106290001Sglebius	kq_sig_add,
107290001Sglebius	kq_sig_del,
108290001Sglebius	NULL,
109290001Sglebius	NULL,
110290001Sglebius	1 /* need reinit */,
111290001Sglebius	0,
112290001Sglebius	0
113290001Sglebius};
114290001Sglebius
115290001Sglebiusstatic void *
116290001Sglebiuskq_init(struct event_base *base)
117290001Sglebius{
118290001Sglebius	int kq = -1;
119290001Sglebius	struct kqop *kqueueop = NULL;
120290001Sglebius
121290001Sglebius	if (!(kqueueop = mm_calloc(1, sizeof(struct kqop))))
122290001Sglebius		return (NULL);
123290001Sglebius
124290001Sglebius/* Initialize the kernel queue */
125290001Sglebius
126290001Sglebius	if ((kq = kqueue()) == -1) {
127290001Sglebius		event_warn("kqueue");
128290001Sglebius		goto err;
129290001Sglebius	}
130290001Sglebius
131290001Sglebius	kqueueop->kq = kq;
132290001Sglebius
133290001Sglebius	kqueueop->pid = getpid();
134290001Sglebius
135290001Sglebius	/* Initialize fields */
136290001Sglebius	kqueueop->changes = mm_calloc(NEVENT, sizeof(struct kevent));
137290001Sglebius	if (kqueueop->changes == NULL)
138290001Sglebius		goto err;
139290001Sglebius	kqueueop->events = mm_calloc(NEVENT, sizeof(struct kevent));
140290001Sglebius	if (kqueueop->events == NULL)
141290001Sglebius		goto err;
142290001Sglebius	kqueueop->events_size = kqueueop->changes_size = NEVENT;
143290001Sglebius
144290001Sglebius	/* Check for Mac OS X kqueue bug. */
145290001Sglebius	memset(&kqueueop->changes[0], 0, sizeof kqueueop->changes[0]);
146290001Sglebius	kqueueop->changes[0].ident = -1;
147290001Sglebius	kqueueop->changes[0].filter = EVFILT_READ;
148290001Sglebius	kqueueop->changes[0].flags = EV_ADD;
149290001Sglebius	/*
150290001Sglebius	 * If kqueue works, then kevent will succeed, and it will
151290001Sglebius	 * stick an error in events[0].  If kqueue is broken, then
152290001Sglebius	 * kevent will fail.
153290001Sglebius	 */
154290001Sglebius	if (kevent(kq,
155290001Sglebius		kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 ||
156290001Sglebius	    (int)kqueueop->events[0].ident != -1 ||
157290001Sglebius	    kqueueop->events[0].flags != EV_ERROR) {
158290001Sglebius		event_warn("%s: detected broken kqueue; not using.", __func__);
159290001Sglebius		goto err;
160290001Sglebius	}
161290001Sglebius
162290001Sglebius	base->evsigsel = &kqsigops;
163290001Sglebius
164290001Sglebius	return (kqueueop);
165290001Sglebiuserr:
166290001Sglebius	if (kqueueop)
167290001Sglebius		kqop_free(kqueueop);
168290001Sglebius
169290001Sglebius	return (NULL);
170290001Sglebius}
171290001Sglebius
172290001Sglebius#define ADD_UDATA 0x30303
173290001Sglebius
174290001Sglebiusstatic void
175290001Sglebiuskq_setup_kevent(struct kevent *out, evutil_socket_t fd, int filter, short change)
176290001Sglebius{
177290001Sglebius	memset(out, 0, sizeof(struct kevent));
178290001Sglebius	out->ident = fd;
179290001Sglebius	out->filter = filter;
180290001Sglebius
181290001Sglebius	if (change & EV_CHANGE_ADD) {
182290001Sglebius		out->flags = EV_ADD;
183290001Sglebius		/* We set a magic number here so that we can tell 'add'
184290001Sglebius		 * errors from 'del' errors. */
185290001Sglebius		out->udata = INT_TO_UDATA(ADD_UDATA);
186290001Sglebius		if (change & EV_ET)
187290001Sglebius			out->flags |= EV_CLEAR;
188290001Sglebius#ifdef NOTE_EOF
189290001Sglebius		/* Make it behave like select() and poll() */
190290001Sglebius		if (filter == EVFILT_READ)
191290001Sglebius			out->fflags = NOTE_EOF;
192290001Sglebius#endif
193290001Sglebius	} else {
194290001Sglebius		EVUTIL_ASSERT(change & EV_CHANGE_DEL);
195290001Sglebius		out->flags = EV_DELETE;
196290001Sglebius	}
197290001Sglebius}
198290001Sglebius
199290001Sglebiusstatic int
200290001Sglebiuskq_build_changes_list(const struct event_changelist *changelist,
201290001Sglebius    struct kqop *kqop)
202290001Sglebius{
203290001Sglebius	int i;
204290001Sglebius	int n_changes = 0;
205290001Sglebius
206290001Sglebius	for (i = 0; i < changelist->n_changes; ++i) {
207290001Sglebius		struct event_change *in_ch = &changelist->changes[i];
208290001Sglebius		struct kevent *out_ch;
209290001Sglebius		if (n_changes >= kqop->changes_size - 1) {
210290001Sglebius			int newsize = kqop->changes_size * 2;
211290001Sglebius			struct kevent *newchanges;
212290001Sglebius
213290001Sglebius			newchanges = mm_realloc(kqop->changes,
214290001Sglebius			    newsize * sizeof(struct kevent));
215290001Sglebius			if (newchanges == NULL) {
216290001Sglebius				event_warn("%s: realloc", __func__);
217290001Sglebius				return (-1);
218290001Sglebius			}
219290001Sglebius			kqop->changes = newchanges;
220290001Sglebius			kqop->changes_size = newsize;
221290001Sglebius		}
222290001Sglebius		if (in_ch->read_change) {
223290001Sglebius			out_ch = &kqop->changes[n_changes++];
224290001Sglebius			kq_setup_kevent(out_ch, in_ch->fd, EVFILT_READ,
225290001Sglebius			    in_ch->read_change);
226290001Sglebius		}
227290001Sglebius		if (in_ch->write_change) {
228290001Sglebius			out_ch = &kqop->changes[n_changes++];
229290001Sglebius			kq_setup_kevent(out_ch, in_ch->fd, EVFILT_WRITE,
230290001Sglebius			    in_ch->write_change);
231290001Sglebius		}
232290001Sglebius	}
233290001Sglebius	return n_changes;
234290001Sglebius}
235290001Sglebius
236290001Sglebiusstatic int
237290001Sglebiuskq_grow_events(struct kqop *kqop, size_t new_size)
238290001Sglebius{
239290001Sglebius	struct kevent *newresult;
240290001Sglebius
241290001Sglebius	newresult = mm_realloc(kqop->events,
242290001Sglebius	    new_size * sizeof(struct kevent));
243290001Sglebius
244290001Sglebius	if (newresult) {
245290001Sglebius		kqop->events = newresult;
246290001Sglebius		kqop->events_size = new_size;
247290001Sglebius		return 0;
248290001Sglebius	} else {
249290001Sglebius		return -1;
250290001Sglebius	}
251290001Sglebius}
252290001Sglebius
253290001Sglebiusstatic int
254290001Sglebiuskq_dispatch(struct event_base *base, struct timeval *tv)
255290001Sglebius{
256290001Sglebius	struct kqop *kqop = base->evbase;
257290001Sglebius	struct kevent *events = kqop->events;
258290001Sglebius	struct kevent *changes;
259290001Sglebius	struct timespec ts, *ts_p = NULL;
260290001Sglebius	int i, n_changes, res;
261290001Sglebius
262290001Sglebius	if (tv != NULL) {
263290001Sglebius		TIMEVAL_TO_TIMESPEC(tv, &ts);
264290001Sglebius		ts_p = &ts;
265290001Sglebius	}
266290001Sglebius
267290001Sglebius	/* Build "changes" from "base->changes" */
268290001Sglebius	EVUTIL_ASSERT(kqop->changes);
269290001Sglebius	n_changes = kq_build_changes_list(&base->changelist, kqop);
270290001Sglebius	if (n_changes < 0)
271290001Sglebius		return -1;
272290001Sglebius
273290001Sglebius	event_changelist_remove_all_(&base->changelist, base);
274290001Sglebius
275290001Sglebius	/* steal the changes array in case some broken code tries to call
276290001Sglebius	 * dispatch twice at once. */
277290001Sglebius	changes = kqop->changes;
278290001Sglebius	kqop->changes = NULL;
279290001Sglebius
280290001Sglebius	/* Make sure that 'events' is at least as long as the list of changes:
281290001Sglebius	 * otherwise errors in the changes can get reported as a -1 return
282290001Sglebius	 * value from kevent() rather than as EV_ERROR events in the events
283290001Sglebius	 * array.
284290001Sglebius	 *
285290001Sglebius	 * (We could instead handle -1 return values from kevent() by
286290001Sglebius	 * retrying with a smaller changes array or a larger events array,
287290001Sglebius	 * but this approach seems less risky for now.)
288290001Sglebius	 */
289290001Sglebius	if (kqop->events_size < n_changes) {
290290001Sglebius		int new_size = kqop->events_size;
291290001Sglebius		do {
292290001Sglebius			new_size *= 2;
293290001Sglebius		} while (new_size < n_changes);
294290001Sglebius
295290001Sglebius		kq_grow_events(kqop, new_size);
296290001Sglebius		events = kqop->events;
297290001Sglebius	}
298290001Sglebius
299290001Sglebius	EVBASE_RELEASE_LOCK(base, th_base_lock);
300290001Sglebius
301290001Sglebius	res = kevent(kqop->kq, changes, n_changes,
302290001Sglebius	    events, kqop->events_size, ts_p);
303290001Sglebius
304290001Sglebius	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
305290001Sglebius
306290001Sglebius	EVUTIL_ASSERT(kqop->changes == NULL);
307290001Sglebius	kqop->changes = changes;
308290001Sglebius
309290001Sglebius	if (res == -1) {
310290001Sglebius		if (errno != EINTR) {
311290001Sglebius			event_warn("kevent");
312290001Sglebius			return (-1);
313290001Sglebius		}
314290001Sglebius
315290001Sglebius		return (0);
316290001Sglebius	}
317290001Sglebius
318290001Sglebius	event_debug(("%s: kevent reports %d", __func__, res));
319290001Sglebius
320290001Sglebius	for (i = 0; i < res; i++) {
321290001Sglebius		int which = 0;
322290001Sglebius
323290001Sglebius		if (events[i].flags & EV_ERROR) {
324290001Sglebius			switch (events[i].data) {
325290001Sglebius
326290001Sglebius			/* Can occur on delete if we are not currently
327290001Sglebius			 * watching any events on this fd.  That can
328290001Sglebius			 * happen when the fd was closed and another
329290001Sglebius			 * file was opened with that fd. */
330290001Sglebius			case ENOENT:
331290001Sglebius			/* Can occur for reasons not fully understood
332290001Sglebius			 * on FreeBSD. */
333290001Sglebius			case EINVAL:
334290001Sglebius				continue;
335290001Sglebius#if defined(__FreeBSD__) && defined(ENOTCAPABLE)
336290001Sglebius			/*
337290001Sglebius			 * This currently occurs if an FD is closed
338290001Sglebius			 * before the EV_DELETE makes it out via kevent().
339290001Sglebius			 * The FreeBSD capabilities code sees the blank
340290001Sglebius			 * capability set and rejects the request to
341290001Sglebius			 * modify an event.
342290001Sglebius			 *
343290001Sglebius			 * To be strictly correct - when an FD is closed,
344290001Sglebius			 * all the registered events are also removed.
345290001Sglebius			 * Queuing EV_DELETE to a closed FD is wrong.
346290001Sglebius			 * The event(s) should just be deleted from
347290001Sglebius			 * the pending changelist.
348290001Sglebius			 */
349290001Sglebius			case ENOTCAPABLE:
350290001Sglebius				continue;
351290001Sglebius#endif
352290001Sglebius
353290001Sglebius			/* Can occur on a delete if the fd is closed. */
354290001Sglebius			case EBADF:
355290001Sglebius				/* XXXX On NetBSD, we can also get EBADF if we
356290001Sglebius				 * try to add the write side of a pipe, but
357290001Sglebius				 * the read side has already been closed.
358290001Sglebius				 * Other BSDs call this situation 'EPIPE'. It
359290001Sglebius				 * would be good if we had a way to report
360290001Sglebius				 * this situation. */
361290001Sglebius				continue;
362290001Sglebius			/* These two can occur on an add if the fd was one side
363290001Sglebius			 * of a pipe, and the other side was closed. */
364290001Sglebius			case EPERM:
365290001Sglebius			case EPIPE:
366290001Sglebius				/* Report read events, if we're listening for
367290001Sglebius				 * them, so that the user can learn about any
368290001Sglebius				 * add errors.  (If the operation was a
369290001Sglebius				 * delete, then udata should be cleared.) */
370290001Sglebius				if (events[i].udata) {
371290001Sglebius					/* The operation was an add:
372290001Sglebius					 * report the error as a read. */
373290001Sglebius					which |= EV_READ;
374290001Sglebius					break;
375290001Sglebius				} else {
376290001Sglebius					/* The operation was a del:
377290001Sglebius					 * report nothing. */
378290001Sglebius					continue;
379290001Sglebius				}
380290001Sglebius
381290001Sglebius			/* Other errors shouldn't occur. */
382290001Sglebius			default:
383290001Sglebius				errno = events[i].data;
384290001Sglebius				return (-1);
385290001Sglebius			}
386290001Sglebius		} else if (events[i].filter == EVFILT_READ) {
387290001Sglebius			which |= EV_READ;
388290001Sglebius		} else if (events[i].filter == EVFILT_WRITE) {
389290001Sglebius			which |= EV_WRITE;
390290001Sglebius		} else if (events[i].filter == EVFILT_SIGNAL) {
391290001Sglebius			which |= EV_SIGNAL;
392290001Sglebius#ifdef EVFILT_USER
393290001Sglebius		} else if (events[i].filter == EVFILT_USER) {
394290001Sglebius			base->is_notify_pending = 0;
395290001Sglebius#endif
396290001Sglebius		}
397290001Sglebius
398290001Sglebius		if (!which)
399290001Sglebius			continue;
400290001Sglebius
401290001Sglebius		if (events[i].filter == EVFILT_SIGNAL) {
402290001Sglebius			evmap_signal_active_(base, events[i].ident, 1);
403290001Sglebius		} else {
404290001Sglebius			evmap_io_active_(base, events[i].ident, which | EV_ET);
405290001Sglebius		}
406290001Sglebius	}
407290001Sglebius
408290001Sglebius	if (res == kqop->events_size) {
409290001Sglebius		/* We used all the events space that we have. Maybe we should
410290001Sglebius		   make it bigger. */
411290001Sglebius		kq_grow_events(kqop, kqop->events_size * 2);
412290001Sglebius	}
413290001Sglebius
414290001Sglebius	return (0);
415290001Sglebius}
416290001Sglebius
417290001Sglebiusstatic void
418290001Sglebiuskqop_free(struct kqop *kqop)
419290001Sglebius{
420290001Sglebius	if (kqop->changes)
421290001Sglebius		mm_free(kqop->changes);
422290001Sglebius	if (kqop->events)
423290001Sglebius		mm_free(kqop->events);
424290001Sglebius	if (kqop->kq >= 0 && kqop->pid == getpid())
425290001Sglebius		close(kqop->kq);
426290001Sglebius	memset(kqop, 0, sizeof(struct kqop));
427290001Sglebius	mm_free(kqop);
428290001Sglebius}
429290001Sglebius
430290001Sglebiusstatic void
431290001Sglebiuskq_dealloc(struct event_base *base)
432290001Sglebius{
433290001Sglebius	struct kqop *kqop = base->evbase;
434290001Sglebius	evsig_dealloc_(base);
435290001Sglebius	kqop_free(kqop);
436290001Sglebius}
437290001Sglebius
438290001Sglebius/* signal handling */
439290001Sglebiusstatic int
440290001Sglebiuskq_sig_add(struct event_base *base, int nsignal, short old, short events, void *p)
441290001Sglebius{
442290001Sglebius	struct kqop *kqop = base->evbase;
443290001Sglebius	struct kevent kev;
444290001Sglebius	struct timespec timeout = { 0, 0 };
445290001Sglebius	(void)p;
446290001Sglebius
447290001Sglebius	EVUTIL_ASSERT(nsignal >= 0 && nsignal < NSIG);
448290001Sglebius
449290001Sglebius	memset(&kev, 0, sizeof(kev));
450290001Sglebius	kev.ident = nsignal;
451290001Sglebius	kev.filter = EVFILT_SIGNAL;
452290001Sglebius	kev.flags = EV_ADD;
453290001Sglebius
454290001Sglebius	/* Be ready for the signal if it is sent any
455290001Sglebius	 * time between now and the next call to
456290001Sglebius	 * kq_dispatch. */
457290001Sglebius	if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
458290001Sglebius		return (-1);
459290001Sglebius
460290001Sglebius        /* We can set the handler for most signals to SIG_IGN and
461290001Sglebius         * still have them reported to us in the queue.  However,
462290001Sglebius         * if the handler for SIGCHLD is SIG_IGN, the system reaps
463290001Sglebius         * zombie processes for us, and we don't get any notification.
464290001Sglebius         * This appears to be the only signal with this quirk. */
465290001Sglebius	if (evsig_set_handler_(base, nsignal,
466290001Sglebius                               nsignal == SIGCHLD ? SIG_DFL : SIG_IGN) == -1)
467290001Sglebius		return (-1);
468290001Sglebius
469290001Sglebius	return (0);
470290001Sglebius}
471290001Sglebius
472290001Sglebiusstatic int
473290001Sglebiuskq_sig_del(struct event_base *base, int nsignal, short old, short events, void *p)
474290001Sglebius{
475290001Sglebius	struct kqop *kqop = base->evbase;
476290001Sglebius	struct kevent kev;
477290001Sglebius
478290001Sglebius	struct timespec timeout = { 0, 0 };
479290001Sglebius	(void)p;
480290001Sglebius
481290001Sglebius	EVUTIL_ASSERT(nsignal >= 0 && nsignal < NSIG);
482290001Sglebius
483290001Sglebius	memset(&kev, 0, sizeof(kev));
484290001Sglebius	kev.ident = nsignal;
485290001Sglebius	kev.filter = EVFILT_SIGNAL;
486290001Sglebius	kev.flags = EV_DELETE;
487290001Sglebius
488290001Sglebius	/* Because we insert signal events
489290001Sglebius	 * immediately, we need to delete them
490290001Sglebius	 * immediately, too */
491290001Sglebius	if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
492290001Sglebius		return (-1);
493290001Sglebius
494290001Sglebius	if (evsig_restore_handler_(base, nsignal) == -1)
495290001Sglebius		return (-1);
496290001Sglebius
497290001Sglebius	return (0);
498290001Sglebius}
499290001Sglebius
500290001Sglebius
501290001Sglebius/* OSX 10.6 and FreeBSD 8.1 add support for EVFILT_USER, which we can use
502290001Sglebius * to wake up the event loop from another thread. */
503290001Sglebius
504290001Sglebius/* Magic number we use for our filter ID. */
505290001Sglebius#define NOTIFY_IDENT 42
506290001Sglebius
507290001Sglebiusint
508290001Sglebiusevent_kq_add_notify_event_(struct event_base *base)
509290001Sglebius{
510290001Sglebius	struct kqop *kqop = base->evbase;
511290001Sglebius#if defined(EVFILT_USER) && defined(NOTE_TRIGGER)
512290001Sglebius	struct kevent kev;
513290001Sglebius	struct timespec timeout = { 0, 0 };
514290001Sglebius#endif
515290001Sglebius
516290001Sglebius	if (kqop->notify_event_added)
517290001Sglebius		return 0;
518290001Sglebius
519290001Sglebius#if defined(EVFILT_USER) && defined(NOTE_TRIGGER)
520290001Sglebius	memset(&kev, 0, sizeof(kev));
521290001Sglebius	kev.ident = NOTIFY_IDENT;
522290001Sglebius	kev.filter = EVFILT_USER;
523290001Sglebius	kev.flags = EV_ADD | EV_CLEAR;
524290001Sglebius
525290001Sglebius	if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1) {
526290001Sglebius		event_warn("kevent: adding EVFILT_USER event");
527290001Sglebius		return -1;
528290001Sglebius	}
529290001Sglebius
530290001Sglebius	kqop->notify_event_added = 1;
531290001Sglebius
532290001Sglebius	return 0;
533290001Sglebius#else
534290001Sglebius	return -1;
535290001Sglebius#endif
536290001Sglebius}
537290001Sglebius
538290001Sglebiusint
539290001Sglebiusevent_kq_notify_base_(struct event_base *base)
540290001Sglebius{
541290001Sglebius	struct kqop *kqop = base->evbase;
542290001Sglebius#if defined(EVFILT_USER) && defined(NOTE_TRIGGER)
543290001Sglebius	struct kevent kev;
544290001Sglebius	struct timespec timeout = { 0, 0 };
545290001Sglebius#endif
546290001Sglebius	if (! kqop->notify_event_added)
547290001Sglebius		return -1;
548290001Sglebius
549290001Sglebius#if defined(EVFILT_USER) && defined(NOTE_TRIGGER)
550290001Sglebius	memset(&kev, 0, sizeof(kev));
551290001Sglebius	kev.ident = NOTIFY_IDENT;
552290001Sglebius	kev.filter = EVFILT_USER;
553290001Sglebius	kev.fflags = NOTE_TRIGGER;
554290001Sglebius
555290001Sglebius	if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1) {
556290001Sglebius		event_warn("kevent: triggering EVFILT_USER event");
557290001Sglebius		return -1;
558290001Sglebius	}
559290001Sglebius
560290001Sglebius	return 0;
561290001Sglebius#else
562290001Sglebius	return -1;
563290001Sglebius#endif
564290001Sglebius}
565290001Sglebius
566290001Sglebius#endif /* EVENT__HAVE_KQUEUE */
567