xref: /freebsd/contrib/pf/libevent/kqueue.c (revision 67ecd4f3a477a0ca5b76a1694f89755df27a8679)
167ecd4f3SMax Laier /*	$OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $	*/
267ecd4f3SMax Laier 
367ecd4f3SMax Laier /*
467ecd4f3SMax Laier  * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
567ecd4f3SMax Laier  * All rights reserved.
667ecd4f3SMax Laier  *
767ecd4f3SMax Laier  * Redistribution and use in source and binary forms, with or without
867ecd4f3SMax Laier  * modification, are permitted provided that the following conditions
967ecd4f3SMax Laier  * are met:
1067ecd4f3SMax Laier  * 1. Redistributions of source code must retain the above copyright
1167ecd4f3SMax Laier  *    notice, this list of conditions and the following disclaimer.
1267ecd4f3SMax Laier  * 2. Redistributions in binary form must reproduce the above copyright
1367ecd4f3SMax Laier  *    notice, this list of conditions and the following disclaimer in the
1467ecd4f3SMax Laier  *    documentation and/or other materials provided with the distribution.
1567ecd4f3SMax Laier  * 3. The name of the author may not be used to endorse or promote products
1667ecd4f3SMax Laier  *    derived from this software without specific prior written permission.
1767ecd4f3SMax Laier  *
1867ecd4f3SMax Laier  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1967ecd4f3SMax Laier  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2067ecd4f3SMax Laier  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2167ecd4f3SMax Laier  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2267ecd4f3SMax Laier  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2367ecd4f3SMax Laier  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2467ecd4f3SMax Laier  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2567ecd4f3SMax Laier  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2667ecd4f3SMax Laier  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2767ecd4f3SMax Laier  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2867ecd4f3SMax Laier  */
2967ecd4f3SMax Laier #ifdef HAVE_CONFIG_H
3067ecd4f3SMax Laier #include "config.h"
3167ecd4f3SMax Laier #endif
3267ecd4f3SMax Laier 
3367ecd4f3SMax Laier #include <sys/types.h>
3467ecd4f3SMax Laier #ifdef HAVE_SYS_TIME_H
3567ecd4f3SMax Laier #include <sys/time.h>
3667ecd4f3SMax Laier #else
3767ecd4f3SMax Laier #include <sys/_time.h>
3867ecd4f3SMax Laier #endif
3967ecd4f3SMax Laier #include <sys/queue.h>
4067ecd4f3SMax Laier #include <sys/event.h>
4167ecd4f3SMax Laier #include <signal.h>
4267ecd4f3SMax Laier #include <stdio.h>
4367ecd4f3SMax Laier #include <stdlib.h>
4467ecd4f3SMax Laier #include <string.h>
4567ecd4f3SMax Laier #include <unistd.h>
4667ecd4f3SMax Laier #include <errno.h>
4767ecd4f3SMax Laier #ifdef HAVE_INTTYPES_H
4867ecd4f3SMax Laier #include <inttypes.h>
4967ecd4f3SMax Laier #endif
5067ecd4f3SMax Laier 
5167ecd4f3SMax Laier #if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__)
5267ecd4f3SMax Laier #define INTPTR(x)	(intptr_t)x
5367ecd4f3SMax Laier #else
5467ecd4f3SMax Laier #define INTPTR(x)	x
5567ecd4f3SMax Laier #endif
5667ecd4f3SMax Laier 
5767ecd4f3SMax Laier #include "event.h"
5867ecd4f3SMax Laier #include "log.h"
5967ecd4f3SMax Laier 
6067ecd4f3SMax Laier #define EVLIST_X_KQINKERNEL	0x1000
6167ecd4f3SMax Laier 
6267ecd4f3SMax Laier #define NEVENT		64
6367ecd4f3SMax Laier 
6467ecd4f3SMax Laier struct kqop {
6567ecd4f3SMax Laier 	struct kevent *changes;
6667ecd4f3SMax Laier 	int nchanges;
6767ecd4f3SMax Laier 	struct kevent *events;
6867ecd4f3SMax Laier 	int nevents;
6967ecd4f3SMax Laier 	int kq;
7067ecd4f3SMax Laier };
7167ecd4f3SMax Laier 
7267ecd4f3SMax Laier void *kq_init	(void);
7367ecd4f3SMax Laier int kq_add	(void *, struct event *);
7467ecd4f3SMax Laier int kq_del	(void *, struct event *);
7567ecd4f3SMax Laier int kq_recalc	(struct event_base *, void *, int);
7667ecd4f3SMax Laier int kq_dispatch	(struct event_base *, void *, struct timeval *);
7767ecd4f3SMax Laier int kq_insert	(struct kqop *, struct kevent *);
7867ecd4f3SMax Laier void kq_dealloc (void *);
7967ecd4f3SMax Laier 
8067ecd4f3SMax Laier const struct eventop kqops = {
8167ecd4f3SMax Laier 	"kqueue",
8267ecd4f3SMax Laier 	kq_init,
8367ecd4f3SMax Laier 	kq_add,
8467ecd4f3SMax Laier 	kq_del,
8567ecd4f3SMax Laier 	kq_recalc,
8667ecd4f3SMax Laier 	kq_dispatch,
8767ecd4f3SMax Laier 	kq_dealloc
8867ecd4f3SMax Laier };
8967ecd4f3SMax Laier 
9067ecd4f3SMax Laier void *
kq_init(void)9167ecd4f3SMax Laier kq_init(void)
9267ecd4f3SMax Laier {
9367ecd4f3SMax Laier 	int kq;
9467ecd4f3SMax Laier 	struct kqop *kqueueop;
9567ecd4f3SMax Laier 
9667ecd4f3SMax Laier 	/* Disable kqueue when this environment variable is set */
9767ecd4f3SMax Laier 	if (getenv("EVENT_NOKQUEUE"))
9867ecd4f3SMax Laier 		return (NULL);
9967ecd4f3SMax Laier 
10067ecd4f3SMax Laier 	if (!(kqueueop = calloc(1, sizeof(struct kqop))))
10167ecd4f3SMax Laier 		return (NULL);
10267ecd4f3SMax Laier 
10367ecd4f3SMax Laier 	/* Initalize the kernel queue */
10467ecd4f3SMax Laier 
10567ecd4f3SMax Laier 	if ((kq = kqueue()) == -1) {
10667ecd4f3SMax Laier 		event_warn("kqueue");
10767ecd4f3SMax Laier 		free (kqueueop);
10867ecd4f3SMax Laier 		return (NULL);
10967ecd4f3SMax Laier 	}
11067ecd4f3SMax Laier 
11167ecd4f3SMax Laier 	kqueueop->kq = kq;
11267ecd4f3SMax Laier 
11367ecd4f3SMax Laier 	/* Initalize fields */
11467ecd4f3SMax Laier 	kqueueop->changes = malloc(NEVENT * sizeof(struct kevent));
11567ecd4f3SMax Laier 	if (kqueueop->changes == NULL) {
11667ecd4f3SMax Laier 		free (kqueueop);
11767ecd4f3SMax Laier 		return (NULL);
11867ecd4f3SMax Laier 	}
11967ecd4f3SMax Laier 	kqueueop->events = malloc(NEVENT * sizeof(struct kevent));
12067ecd4f3SMax Laier 	if (kqueueop->events == NULL) {
12167ecd4f3SMax Laier 		free (kqueueop->changes);
12267ecd4f3SMax Laier 		free (kqueueop);
12367ecd4f3SMax Laier 		return (NULL);
12467ecd4f3SMax Laier 	}
12567ecd4f3SMax Laier 	kqueueop->nevents = NEVENT;
12667ecd4f3SMax Laier 
12767ecd4f3SMax Laier 	/* Check for Mac OS X kqueue bug. */
12867ecd4f3SMax Laier 	kqueueop->changes[0].ident = -1;
12967ecd4f3SMax Laier 	kqueueop->changes[0].filter = EVFILT_READ;
13067ecd4f3SMax Laier 	kqueueop->changes[0].flags = EV_ADD;
13167ecd4f3SMax Laier 	/*
13267ecd4f3SMax Laier 	 * If kqueue works, then kevent will succeed, and it will
13367ecd4f3SMax Laier 	 * stick an error in events[0].  If kqueue is broken, then
13467ecd4f3SMax Laier 	 * kevent will fail.
13567ecd4f3SMax Laier 	 */
13667ecd4f3SMax Laier 	if (kevent(kq,
13767ecd4f3SMax Laier 		kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 ||
13867ecd4f3SMax Laier 	    kqueueop->events[0].ident != -1 ||
13967ecd4f3SMax Laier 	    kqueueop->events[0].flags != EV_ERROR) {
14067ecd4f3SMax Laier 		event_warn("%s: detected broken kqueue; not using.", __func__);
14167ecd4f3SMax Laier 		free(kqueueop->changes);
14267ecd4f3SMax Laier 		free(kqueueop->events);
14367ecd4f3SMax Laier 		free(kqueueop);
14467ecd4f3SMax Laier 		close(kq);
14567ecd4f3SMax Laier 		return (NULL);
14667ecd4f3SMax Laier 	}
14767ecd4f3SMax Laier 
14867ecd4f3SMax Laier 	return (kqueueop);
14967ecd4f3SMax Laier }
15067ecd4f3SMax Laier 
15167ecd4f3SMax Laier int
kq_recalc(struct event_base * base,void * arg,int max)15267ecd4f3SMax Laier kq_recalc(struct event_base *base, void *arg, int max)
15367ecd4f3SMax Laier {
15467ecd4f3SMax Laier 	return (0);
15567ecd4f3SMax Laier }
15667ecd4f3SMax Laier 
15767ecd4f3SMax Laier int
kq_insert(struct kqop * kqop,struct kevent * kev)15867ecd4f3SMax Laier kq_insert(struct kqop *kqop, struct kevent *kev)
15967ecd4f3SMax Laier {
16067ecd4f3SMax Laier 	int nevents = kqop->nevents;
16167ecd4f3SMax Laier 
16267ecd4f3SMax Laier 	if (kqop->nchanges == nevents) {
16367ecd4f3SMax Laier 		struct kevent *newchange;
16467ecd4f3SMax Laier 		struct kevent *newresult;
16567ecd4f3SMax Laier 
16667ecd4f3SMax Laier 		nevents *= 2;
16767ecd4f3SMax Laier 
16867ecd4f3SMax Laier 		newchange = realloc(kqop->changes,
16967ecd4f3SMax Laier 				    nevents * sizeof(struct kevent));
17067ecd4f3SMax Laier 		if (newchange == NULL) {
17167ecd4f3SMax Laier 			event_warn("%s: malloc", __func__);
17267ecd4f3SMax Laier 			return (-1);
17367ecd4f3SMax Laier 		}
17467ecd4f3SMax Laier 		kqop->changes = newchange;
17567ecd4f3SMax Laier 
17667ecd4f3SMax Laier 		newresult = realloc(kqop->events,
17767ecd4f3SMax Laier 				    nevents * sizeof(struct kevent));
17867ecd4f3SMax Laier 
17967ecd4f3SMax Laier 		/*
18067ecd4f3SMax Laier 		 * If we fail, we don't have to worry about freeing,
18167ecd4f3SMax Laier 		 * the next realloc will pick it up.
18267ecd4f3SMax Laier 		 */
18367ecd4f3SMax Laier 		if (newresult == NULL) {
18467ecd4f3SMax Laier 			event_warn("%s: malloc", __func__);
18567ecd4f3SMax Laier 			return (-1);
18667ecd4f3SMax Laier 		}
18767ecd4f3SMax Laier 		kqop->events = newresult;
18867ecd4f3SMax Laier 
18967ecd4f3SMax Laier 		kqop->nevents = nevents;
19067ecd4f3SMax Laier 	}
19167ecd4f3SMax Laier 
19267ecd4f3SMax Laier 	memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
19367ecd4f3SMax Laier 
19467ecd4f3SMax Laier 	event_debug(("%s: fd %d %s%s",
19567ecd4f3SMax Laier 		 __func__, kev->ident,
19667ecd4f3SMax Laier 		 kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
19767ecd4f3SMax Laier 		 kev->flags == EV_DELETE ? " (del)" : ""));
19867ecd4f3SMax Laier 
19967ecd4f3SMax Laier 	return (0);
20067ecd4f3SMax Laier }
20167ecd4f3SMax Laier 
20267ecd4f3SMax Laier static void
kq_sighandler(int sig)20367ecd4f3SMax Laier kq_sighandler(int sig)
20467ecd4f3SMax Laier {
20567ecd4f3SMax Laier 	/* Do nothing here */
20667ecd4f3SMax Laier }
20767ecd4f3SMax Laier 
20867ecd4f3SMax Laier int
kq_dispatch(struct event_base * base,void * arg,struct timeval * tv)20967ecd4f3SMax Laier kq_dispatch(struct event_base *base, void *arg, struct timeval *tv)
21067ecd4f3SMax Laier {
21167ecd4f3SMax Laier 	struct kqop *kqop = arg;
21267ecd4f3SMax Laier 	struct kevent *changes = kqop->changes;
21367ecd4f3SMax Laier 	struct kevent *events = kqop->events;
21467ecd4f3SMax Laier 	struct event *ev;
21567ecd4f3SMax Laier 	struct timespec ts;
21667ecd4f3SMax Laier 	int i, res;
21767ecd4f3SMax Laier 
21867ecd4f3SMax Laier 	TIMEVAL_TO_TIMESPEC(tv, &ts);
21967ecd4f3SMax Laier 
22067ecd4f3SMax Laier 	res = kevent(kqop->kq, changes, kqop->nchanges,
22167ecd4f3SMax Laier 	    events, kqop->nevents, &ts);
22267ecd4f3SMax Laier 	kqop->nchanges = 0;
22367ecd4f3SMax Laier 	if (res == -1) {
22467ecd4f3SMax Laier 		if (errno != EINTR) {
22567ecd4f3SMax Laier                         event_warn("kevent");
22667ecd4f3SMax Laier 			return (-1);
22767ecd4f3SMax Laier 		}
22867ecd4f3SMax Laier 
22967ecd4f3SMax Laier 		return (0);
23067ecd4f3SMax Laier 	}
23167ecd4f3SMax Laier 
23267ecd4f3SMax Laier 	event_debug(("%s: kevent reports %d", __func__, res));
23367ecd4f3SMax Laier 
23467ecd4f3SMax Laier 	for (i = 0; i < res; i++) {
23567ecd4f3SMax Laier 		int which = 0;
23667ecd4f3SMax Laier 
23767ecd4f3SMax Laier 		if (events[i].flags & EV_ERROR) {
23867ecd4f3SMax Laier 			/*
23967ecd4f3SMax Laier 			 * Error messages that can happen, when a delete fails.
24067ecd4f3SMax Laier 			 *   EBADF happens when the file discriptor has been
24167ecd4f3SMax Laier 			 *   closed,
24267ecd4f3SMax Laier 			 *   ENOENT when the file discriptor was closed and
24367ecd4f3SMax Laier 			 *   then reopened.
24467ecd4f3SMax Laier 			 *   EINVAL for some reasons not understood; EINVAL
24567ecd4f3SMax Laier 			 *   should not be returned ever; but FreeBSD does :-\
24667ecd4f3SMax Laier 			 * An error is also indicated when a callback deletes
24767ecd4f3SMax Laier 			 * an event we are still processing.  In that case
24867ecd4f3SMax Laier 			 * the data field is set to ENOENT.
24967ecd4f3SMax Laier 			 */
25067ecd4f3SMax Laier 			if (events[i].data == EBADF ||
25167ecd4f3SMax Laier 			    events[i].data == EINVAL ||
25267ecd4f3SMax Laier 			    events[i].data == ENOENT)
25367ecd4f3SMax Laier 				continue;
25467ecd4f3SMax Laier 			errno = events[i].data;
25567ecd4f3SMax Laier 			return (-1);
25667ecd4f3SMax Laier 		}
25767ecd4f3SMax Laier 
25867ecd4f3SMax Laier 		ev = (struct event *)events[i].udata;
25967ecd4f3SMax Laier 
26067ecd4f3SMax Laier 		if (events[i].filter == EVFILT_READ) {
26167ecd4f3SMax Laier 			which |= EV_READ;
26267ecd4f3SMax Laier 		} else if (events[i].filter == EVFILT_WRITE) {
26367ecd4f3SMax Laier 			which |= EV_WRITE;
26467ecd4f3SMax Laier 		} else if (events[i].filter == EVFILT_SIGNAL) {
26567ecd4f3SMax Laier 			which |= EV_SIGNAL;
26667ecd4f3SMax Laier 		}
26767ecd4f3SMax Laier 
26867ecd4f3SMax Laier 		if (!which)
26967ecd4f3SMax Laier 			continue;
27067ecd4f3SMax Laier 
27167ecd4f3SMax Laier 		if (!(ev->ev_events & EV_PERSIST))
27267ecd4f3SMax Laier 			event_del(ev);
27367ecd4f3SMax Laier 
27467ecd4f3SMax Laier 		event_active(ev, which,
27567ecd4f3SMax Laier 		    ev->ev_events & EV_SIGNAL ? events[i].data : 1);
27667ecd4f3SMax Laier 	}
27767ecd4f3SMax Laier 
27867ecd4f3SMax Laier 	return (0);
27967ecd4f3SMax Laier }
28067ecd4f3SMax Laier 
28167ecd4f3SMax Laier 
28267ecd4f3SMax Laier int
kq_add(void * arg,struct event * ev)28367ecd4f3SMax Laier kq_add(void *arg, struct event *ev)
28467ecd4f3SMax Laier {
28567ecd4f3SMax Laier 	struct kqop *kqop = arg;
28667ecd4f3SMax Laier 	struct kevent kev;
28767ecd4f3SMax Laier 
28867ecd4f3SMax Laier 	if (ev->ev_events & EV_SIGNAL) {
28967ecd4f3SMax Laier 		int nsignal = EVENT_SIGNAL(ev);
29067ecd4f3SMax Laier 
29167ecd4f3SMax Laier  		memset(&kev, 0, sizeof(kev));
29267ecd4f3SMax Laier 		kev.ident = nsignal;
29367ecd4f3SMax Laier 		kev.filter = EVFILT_SIGNAL;
29467ecd4f3SMax Laier 		kev.flags = EV_ADD;
29567ecd4f3SMax Laier 		if (!(ev->ev_events & EV_PERSIST))
29667ecd4f3SMax Laier 			kev.flags |= EV_ONESHOT;
29767ecd4f3SMax Laier 		kev.udata = INTPTR(ev);
29867ecd4f3SMax Laier 
29967ecd4f3SMax Laier 		if (kq_insert(kqop, &kev) == -1)
30067ecd4f3SMax Laier 			return (-1);
30167ecd4f3SMax Laier 
30267ecd4f3SMax Laier 		if (signal(nsignal, kq_sighandler) == SIG_ERR)
30367ecd4f3SMax Laier 			return (-1);
30467ecd4f3SMax Laier 
30567ecd4f3SMax Laier 		ev->ev_flags |= EVLIST_X_KQINKERNEL;
30667ecd4f3SMax Laier 		return (0);
30767ecd4f3SMax Laier 	}
30867ecd4f3SMax Laier 
30967ecd4f3SMax Laier 	if (ev->ev_events & EV_READ) {
31067ecd4f3SMax Laier  		memset(&kev, 0, sizeof(kev));
31167ecd4f3SMax Laier 		kev.ident = ev->ev_fd;
31267ecd4f3SMax Laier 		kev.filter = EVFILT_READ;
31367ecd4f3SMax Laier #ifdef NOTE_EOF
31467ecd4f3SMax Laier 		/* Make it behave like select() and poll() */
31567ecd4f3SMax Laier 		kev.fflags = NOTE_EOF;
31667ecd4f3SMax Laier #endif
31767ecd4f3SMax Laier 		kev.flags = EV_ADD;
31867ecd4f3SMax Laier 		if (!(ev->ev_events & EV_PERSIST))
31967ecd4f3SMax Laier 			kev.flags |= EV_ONESHOT;
32067ecd4f3SMax Laier 		kev.udata = INTPTR(ev);
32167ecd4f3SMax Laier 
32267ecd4f3SMax Laier 		if (kq_insert(kqop, &kev) == -1)
32367ecd4f3SMax Laier 			return (-1);
32467ecd4f3SMax Laier 
32567ecd4f3SMax Laier 		ev->ev_flags |= EVLIST_X_KQINKERNEL;
32667ecd4f3SMax Laier 	}
32767ecd4f3SMax Laier 
32867ecd4f3SMax Laier 	if (ev->ev_events & EV_WRITE) {
32967ecd4f3SMax Laier  		memset(&kev, 0, sizeof(kev));
33067ecd4f3SMax Laier 		kev.ident = ev->ev_fd;
33167ecd4f3SMax Laier 		kev.filter = EVFILT_WRITE;
33267ecd4f3SMax Laier 		kev.flags = EV_ADD;
33367ecd4f3SMax Laier 		if (!(ev->ev_events & EV_PERSIST))
33467ecd4f3SMax Laier 			kev.flags |= EV_ONESHOT;
33567ecd4f3SMax Laier 		kev.udata = INTPTR(ev);
33667ecd4f3SMax Laier 
33767ecd4f3SMax Laier 		if (kq_insert(kqop, &kev) == -1)
33867ecd4f3SMax Laier 			return (-1);
33967ecd4f3SMax Laier 
34067ecd4f3SMax Laier 		ev->ev_flags |= EVLIST_X_KQINKERNEL;
34167ecd4f3SMax Laier 	}
34267ecd4f3SMax Laier 
34367ecd4f3SMax Laier 	return (0);
34467ecd4f3SMax Laier }
34567ecd4f3SMax Laier 
34667ecd4f3SMax Laier int
kq_del(void * arg,struct event * ev)34767ecd4f3SMax Laier kq_del(void *arg, struct event *ev)
34867ecd4f3SMax Laier {
34967ecd4f3SMax Laier 	struct kqop *kqop = arg;
35067ecd4f3SMax Laier 	struct kevent kev;
35167ecd4f3SMax Laier 
35267ecd4f3SMax Laier 	if (!(ev->ev_flags & EVLIST_X_KQINKERNEL))
35367ecd4f3SMax Laier 		return (0);
35467ecd4f3SMax Laier 
35567ecd4f3SMax Laier 	if (ev->ev_events & EV_SIGNAL) {
35667ecd4f3SMax Laier 		int nsignal = EVENT_SIGNAL(ev);
35767ecd4f3SMax Laier 
35867ecd4f3SMax Laier  		memset(&kev, 0, sizeof(kev));
35967ecd4f3SMax Laier 		kev.ident = nsignal;
36067ecd4f3SMax Laier 		kev.filter = EVFILT_SIGNAL;
36167ecd4f3SMax Laier 		kev.flags = EV_DELETE;
36267ecd4f3SMax Laier 
36367ecd4f3SMax Laier 		if (kq_insert(kqop, &kev) == -1)
36467ecd4f3SMax Laier 			return (-1);
36567ecd4f3SMax Laier 
36667ecd4f3SMax Laier 		if (signal(nsignal, SIG_DFL) == SIG_ERR)
36767ecd4f3SMax Laier 			return (-1);
36867ecd4f3SMax Laier 
36967ecd4f3SMax Laier 		ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
37067ecd4f3SMax Laier 		return (0);
37167ecd4f3SMax Laier 	}
37267ecd4f3SMax Laier 
37367ecd4f3SMax Laier 	if (ev->ev_events & EV_READ) {
37467ecd4f3SMax Laier  		memset(&kev, 0, sizeof(kev));
37567ecd4f3SMax Laier 		kev.ident = ev->ev_fd;
37667ecd4f3SMax Laier 		kev.filter = EVFILT_READ;
37767ecd4f3SMax Laier 		kev.flags = EV_DELETE;
37867ecd4f3SMax Laier 
37967ecd4f3SMax Laier 		if (kq_insert(kqop, &kev) == -1)
38067ecd4f3SMax Laier 			return (-1);
38167ecd4f3SMax Laier 
38267ecd4f3SMax Laier 		ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
38367ecd4f3SMax Laier 	}
38467ecd4f3SMax Laier 
38567ecd4f3SMax Laier 	if (ev->ev_events & EV_WRITE) {
38667ecd4f3SMax Laier  		memset(&kev, 0, sizeof(kev));
38767ecd4f3SMax Laier 		kev.ident = ev->ev_fd;
38867ecd4f3SMax Laier 		kev.filter = EVFILT_WRITE;
38967ecd4f3SMax Laier 		kev.flags = EV_DELETE;
39067ecd4f3SMax Laier 
39167ecd4f3SMax Laier 		if (kq_insert(kqop, &kev) == -1)
39267ecd4f3SMax Laier 			return (-1);
39367ecd4f3SMax Laier 
39467ecd4f3SMax Laier 		ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
39567ecd4f3SMax Laier 	}
39667ecd4f3SMax Laier 
39767ecd4f3SMax Laier 	return (0);
39867ecd4f3SMax Laier }
39967ecd4f3SMax Laier 
40067ecd4f3SMax Laier void
kq_dealloc(void * arg)40167ecd4f3SMax Laier kq_dealloc(void *arg)
40267ecd4f3SMax Laier {
40367ecd4f3SMax Laier 	struct kqop *kqop = arg;
40467ecd4f3SMax Laier 
40567ecd4f3SMax Laier 	if (kqop->changes)
40667ecd4f3SMax Laier 		free(kqop->changes);
40767ecd4f3SMax Laier 	if (kqop->events)
40867ecd4f3SMax Laier 		free(kqop->events);
40967ecd4f3SMax Laier 	if (kqop->kq)
41067ecd4f3SMax Laier 		close(kqop->kq);
41167ecd4f3SMax Laier 	memset(kqop, 0, sizeof(struct kqop));
41267ecd4f3SMax Laier 	free(kqop);
41367ecd4f3SMax Laier }
414