1171169Smlaier/*	$OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $	*/
2171169Smlaier
3171169Smlaier/*
4171169Smlaier * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
5171169Smlaier * All rights reserved.
6171169Smlaier *
7171169Smlaier * Redistribution and use in source and binary forms, with or without
8171169Smlaier * modification, are permitted provided that the following conditions
9171169Smlaier * are met:
10171169Smlaier * 1. Redistributions of source code must retain the above copyright
11171169Smlaier *    notice, this list of conditions and the following disclaimer.
12171169Smlaier * 2. Redistributions in binary form must reproduce the above copyright
13171169Smlaier *    notice, this list of conditions and the following disclaimer in the
14171169Smlaier *    documentation and/or other materials provided with the distribution.
15171169Smlaier * 3. The name of the author may not be used to endorse or promote products
16171169Smlaier *    derived from this software without specific prior written permission.
17171169Smlaier *
18171169Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19171169Smlaier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20171169Smlaier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21171169Smlaier * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22171169Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23171169Smlaier * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24171169Smlaier * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25171169Smlaier * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26171169Smlaier * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27171169Smlaier * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28171169Smlaier */
29171169Smlaier#ifdef HAVE_CONFIG_H
30171169Smlaier#include "config.h"
31171169Smlaier#endif
32171169Smlaier
33171169Smlaier#include <sys/types.h>
34171169Smlaier#ifdef HAVE_SYS_TIME_H
35171169Smlaier#include <sys/time.h>
36171169Smlaier#else
37171169Smlaier#include <sys/_time.h>
38171169Smlaier#endif
39171169Smlaier#include <sys/queue.h>
40171169Smlaier#include <sys/event.h>
41171169Smlaier#include <signal.h>
42171169Smlaier#include <stdio.h>
43171169Smlaier#include <stdlib.h>
44171169Smlaier#include <string.h>
45171169Smlaier#include <unistd.h>
46171169Smlaier#include <errno.h>
47171169Smlaier#ifdef HAVE_INTTYPES_H
48171169Smlaier#include <inttypes.h>
49171169Smlaier#endif
50171169Smlaier
51171169Smlaier#if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__)
52171169Smlaier#define INTPTR(x)	(intptr_t)x
53171169Smlaier#else
54171169Smlaier#define INTPTR(x)	x
55171169Smlaier#endif
56171169Smlaier
57171169Smlaier#include "event.h"
58171169Smlaier#include "log.h"
59171169Smlaier
60171169Smlaier#define EVLIST_X_KQINKERNEL	0x1000
61171169Smlaier
62171169Smlaier#define NEVENT		64
63171169Smlaier
64171169Smlaierstruct kqop {
65171169Smlaier	struct kevent *changes;
66171169Smlaier	int nchanges;
67171169Smlaier	struct kevent *events;
68171169Smlaier	int nevents;
69171169Smlaier	int kq;
70171169Smlaier};
71171169Smlaier
72171169Smlaiervoid *kq_init	(void);
73171169Smlaierint kq_add	(void *, struct event *);
74171169Smlaierint kq_del	(void *, struct event *);
75171169Smlaierint kq_recalc	(struct event_base *, void *, int);
76171169Smlaierint kq_dispatch	(struct event_base *, void *, struct timeval *);
77171169Smlaierint kq_insert	(struct kqop *, struct kevent *);
78171169Smlaiervoid kq_dealloc (void *);
79171169Smlaier
80171169Smlaierconst struct eventop kqops = {
81171169Smlaier	"kqueue",
82171169Smlaier	kq_init,
83171169Smlaier	kq_add,
84171169Smlaier	kq_del,
85171169Smlaier	kq_recalc,
86171169Smlaier	kq_dispatch,
87171169Smlaier	kq_dealloc
88171169Smlaier};
89171169Smlaier
90171169Smlaiervoid *
91171169Smlaierkq_init(void)
92171169Smlaier{
93171169Smlaier	int kq;
94171169Smlaier	struct kqop *kqueueop;
95171169Smlaier
96171169Smlaier	/* Disable kqueue when this environment variable is set */
97171169Smlaier	if (getenv("EVENT_NOKQUEUE"))
98171169Smlaier		return (NULL);
99171169Smlaier
100171169Smlaier	if (!(kqueueop = calloc(1, sizeof(struct kqop))))
101171169Smlaier		return (NULL);
102171169Smlaier
103171169Smlaier	/* Initalize the kernel queue */
104171169Smlaier
105171169Smlaier	if ((kq = kqueue()) == -1) {
106171169Smlaier		event_warn("kqueue");
107171169Smlaier		free (kqueueop);
108171169Smlaier		return (NULL);
109171169Smlaier	}
110171169Smlaier
111171169Smlaier	kqueueop->kq = kq;
112171169Smlaier
113171169Smlaier	/* Initalize fields */
114171169Smlaier	kqueueop->changes = malloc(NEVENT * sizeof(struct kevent));
115171169Smlaier	if (kqueueop->changes == NULL) {
116171169Smlaier		free (kqueueop);
117171169Smlaier		return (NULL);
118171169Smlaier	}
119171169Smlaier	kqueueop->events = malloc(NEVENT * sizeof(struct kevent));
120171169Smlaier	if (kqueueop->events == NULL) {
121171169Smlaier		free (kqueueop->changes);
122171169Smlaier		free (kqueueop);
123171169Smlaier		return (NULL);
124171169Smlaier	}
125171169Smlaier	kqueueop->nevents = NEVENT;
126171169Smlaier
127171169Smlaier	/* Check for Mac OS X kqueue bug. */
128171169Smlaier	kqueueop->changes[0].ident = -1;
129171169Smlaier	kqueueop->changes[0].filter = EVFILT_READ;
130171169Smlaier	kqueueop->changes[0].flags = EV_ADD;
131171169Smlaier	/*
132171169Smlaier	 * If kqueue works, then kevent will succeed, and it will
133171169Smlaier	 * stick an error in events[0].  If kqueue is broken, then
134171169Smlaier	 * kevent will fail.
135171169Smlaier	 */
136171169Smlaier	if (kevent(kq,
137171169Smlaier		kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 ||
138171169Smlaier	    kqueueop->events[0].ident != -1 ||
139171169Smlaier	    kqueueop->events[0].flags != EV_ERROR) {
140171169Smlaier		event_warn("%s: detected broken kqueue; not using.", __func__);
141171169Smlaier		free(kqueueop->changes);
142171169Smlaier		free(kqueueop->events);
143171169Smlaier		free(kqueueop);
144171169Smlaier		close(kq);
145171169Smlaier		return (NULL);
146171169Smlaier	}
147171169Smlaier
148171169Smlaier	return (kqueueop);
149171169Smlaier}
150171169Smlaier
151171169Smlaierint
152171169Smlaierkq_recalc(struct event_base *base, void *arg, int max)
153171169Smlaier{
154171169Smlaier	return (0);
155171169Smlaier}
156171169Smlaier
157171169Smlaierint
158171169Smlaierkq_insert(struct kqop *kqop, struct kevent *kev)
159171169Smlaier{
160171169Smlaier	int nevents = kqop->nevents;
161171169Smlaier
162171169Smlaier	if (kqop->nchanges == nevents) {
163171169Smlaier		struct kevent *newchange;
164171169Smlaier		struct kevent *newresult;
165171169Smlaier
166171169Smlaier		nevents *= 2;
167171169Smlaier
168171169Smlaier		newchange = realloc(kqop->changes,
169171169Smlaier				    nevents * sizeof(struct kevent));
170171169Smlaier		if (newchange == NULL) {
171171169Smlaier			event_warn("%s: malloc", __func__);
172171169Smlaier			return (-1);
173171169Smlaier		}
174171169Smlaier		kqop->changes = newchange;
175171169Smlaier
176171169Smlaier		newresult = realloc(kqop->events,
177171169Smlaier				    nevents * sizeof(struct kevent));
178171169Smlaier
179171169Smlaier		/*
180171169Smlaier		 * If we fail, we don't have to worry about freeing,
181171169Smlaier		 * the next realloc will pick it up.
182171169Smlaier		 */
183171169Smlaier		if (newresult == NULL) {
184171169Smlaier			event_warn("%s: malloc", __func__);
185171169Smlaier			return (-1);
186171169Smlaier		}
187171169Smlaier		kqop->events = newresult;
188171169Smlaier
189171169Smlaier		kqop->nevents = nevents;
190171169Smlaier	}
191171169Smlaier
192171169Smlaier	memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
193171169Smlaier
194171169Smlaier	event_debug(("%s: fd %d %s%s",
195171169Smlaier		 __func__, kev->ident,
196171169Smlaier		 kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
197171169Smlaier		 kev->flags == EV_DELETE ? " (del)" : ""));
198171169Smlaier
199171169Smlaier	return (0);
200171169Smlaier}
201171169Smlaier
202171169Smlaierstatic void
203171169Smlaierkq_sighandler(int sig)
204171169Smlaier{
205171169Smlaier	/* Do nothing here */
206171169Smlaier}
207171169Smlaier
208171169Smlaierint
209171169Smlaierkq_dispatch(struct event_base *base, void *arg, struct timeval *tv)
210171169Smlaier{
211171169Smlaier	struct kqop *kqop = arg;
212171169Smlaier	struct kevent *changes = kqop->changes;
213171169Smlaier	struct kevent *events = kqop->events;
214171169Smlaier	struct event *ev;
215171169Smlaier	struct timespec ts;
216171169Smlaier	int i, res;
217171169Smlaier
218171169Smlaier	TIMEVAL_TO_TIMESPEC(tv, &ts);
219171169Smlaier
220171169Smlaier	res = kevent(kqop->kq, changes, kqop->nchanges,
221171169Smlaier	    events, kqop->nevents, &ts);
222171169Smlaier	kqop->nchanges = 0;
223171169Smlaier	if (res == -1) {
224171169Smlaier		if (errno != EINTR) {
225171169Smlaier                        event_warn("kevent");
226171169Smlaier			return (-1);
227171169Smlaier		}
228171169Smlaier
229171169Smlaier		return (0);
230171169Smlaier	}
231171169Smlaier
232171169Smlaier	event_debug(("%s: kevent reports %d", __func__, res));
233171169Smlaier
234171169Smlaier	for (i = 0; i < res; i++) {
235171169Smlaier		int which = 0;
236171169Smlaier
237171169Smlaier		if (events[i].flags & EV_ERROR) {
238171169Smlaier			/*
239171169Smlaier			 * Error messages that can happen, when a delete fails.
240171169Smlaier			 *   EBADF happens when the file discriptor has been
241171169Smlaier			 *   closed,
242171169Smlaier			 *   ENOENT when the file discriptor was closed and
243171169Smlaier			 *   then reopened.
244171169Smlaier			 *   EINVAL for some reasons not understood; EINVAL
245171169Smlaier			 *   should not be returned ever; but FreeBSD does :-\
246171169Smlaier			 * An error is also indicated when a callback deletes
247171169Smlaier			 * an event we are still processing.  In that case
248171169Smlaier			 * the data field is set to ENOENT.
249171169Smlaier			 */
250171169Smlaier			if (events[i].data == EBADF ||
251171169Smlaier			    events[i].data == EINVAL ||
252171169Smlaier			    events[i].data == ENOENT)
253171169Smlaier				continue;
254171169Smlaier			errno = events[i].data;
255171169Smlaier			return (-1);
256171169Smlaier		}
257171169Smlaier
258171169Smlaier		ev = (struct event *)events[i].udata;
259171169Smlaier
260171169Smlaier		if (events[i].filter == EVFILT_READ) {
261171169Smlaier			which |= EV_READ;
262171169Smlaier		} else if (events[i].filter == EVFILT_WRITE) {
263171169Smlaier			which |= EV_WRITE;
264171169Smlaier		} else if (events[i].filter == EVFILT_SIGNAL) {
265171169Smlaier			which |= EV_SIGNAL;
266171169Smlaier		}
267171169Smlaier
268171169Smlaier		if (!which)
269171169Smlaier			continue;
270171169Smlaier
271171169Smlaier		if (!(ev->ev_events & EV_PERSIST))
272171169Smlaier			event_del(ev);
273171169Smlaier
274171169Smlaier		event_active(ev, which,
275171169Smlaier		    ev->ev_events & EV_SIGNAL ? events[i].data : 1);
276171169Smlaier	}
277171169Smlaier
278171169Smlaier	return (0);
279171169Smlaier}
280171169Smlaier
281171169Smlaier
282171169Smlaierint
283171169Smlaierkq_add(void *arg, struct event *ev)
284171169Smlaier{
285171169Smlaier	struct kqop *kqop = arg;
286171169Smlaier	struct kevent kev;
287171169Smlaier
288171169Smlaier	if (ev->ev_events & EV_SIGNAL) {
289171169Smlaier		int nsignal = EVENT_SIGNAL(ev);
290171169Smlaier
291171169Smlaier 		memset(&kev, 0, sizeof(kev));
292171169Smlaier		kev.ident = nsignal;
293171169Smlaier		kev.filter = EVFILT_SIGNAL;
294171169Smlaier		kev.flags = EV_ADD;
295171169Smlaier		if (!(ev->ev_events & EV_PERSIST))
296171169Smlaier			kev.flags |= EV_ONESHOT;
297171169Smlaier		kev.udata = INTPTR(ev);
298171169Smlaier
299171169Smlaier		if (kq_insert(kqop, &kev) == -1)
300171169Smlaier			return (-1);
301171169Smlaier
302171169Smlaier		if (signal(nsignal, kq_sighandler) == SIG_ERR)
303171169Smlaier			return (-1);
304171169Smlaier
305171169Smlaier		ev->ev_flags |= EVLIST_X_KQINKERNEL;
306171169Smlaier		return (0);
307171169Smlaier	}
308171169Smlaier
309171169Smlaier	if (ev->ev_events & EV_READ) {
310171169Smlaier 		memset(&kev, 0, sizeof(kev));
311171169Smlaier		kev.ident = ev->ev_fd;
312171169Smlaier		kev.filter = EVFILT_READ;
313171169Smlaier#ifdef NOTE_EOF
314171169Smlaier		/* Make it behave like select() and poll() */
315171169Smlaier		kev.fflags = NOTE_EOF;
316171169Smlaier#endif
317171169Smlaier		kev.flags = EV_ADD;
318171169Smlaier		if (!(ev->ev_events & EV_PERSIST))
319171169Smlaier			kev.flags |= EV_ONESHOT;
320171169Smlaier		kev.udata = INTPTR(ev);
321171169Smlaier
322171169Smlaier		if (kq_insert(kqop, &kev) == -1)
323171169Smlaier			return (-1);
324171169Smlaier
325171169Smlaier		ev->ev_flags |= EVLIST_X_KQINKERNEL;
326171169Smlaier	}
327171169Smlaier
328171169Smlaier	if (ev->ev_events & EV_WRITE) {
329171169Smlaier 		memset(&kev, 0, sizeof(kev));
330171169Smlaier		kev.ident = ev->ev_fd;
331171169Smlaier		kev.filter = EVFILT_WRITE;
332171169Smlaier		kev.flags = EV_ADD;
333171169Smlaier		if (!(ev->ev_events & EV_PERSIST))
334171169Smlaier			kev.flags |= EV_ONESHOT;
335171169Smlaier		kev.udata = INTPTR(ev);
336171169Smlaier
337171169Smlaier		if (kq_insert(kqop, &kev) == -1)
338171169Smlaier			return (-1);
339171169Smlaier
340171169Smlaier		ev->ev_flags |= EVLIST_X_KQINKERNEL;
341171169Smlaier	}
342171169Smlaier
343171169Smlaier	return (0);
344171169Smlaier}
345171169Smlaier
346171169Smlaierint
347171169Smlaierkq_del(void *arg, struct event *ev)
348171169Smlaier{
349171169Smlaier	struct kqop *kqop = arg;
350171169Smlaier	struct kevent kev;
351171169Smlaier
352171169Smlaier	if (!(ev->ev_flags & EVLIST_X_KQINKERNEL))
353171169Smlaier		return (0);
354171169Smlaier
355171169Smlaier	if (ev->ev_events & EV_SIGNAL) {
356171169Smlaier		int nsignal = EVENT_SIGNAL(ev);
357171169Smlaier
358171169Smlaier 		memset(&kev, 0, sizeof(kev));
359171169Smlaier		kev.ident = nsignal;
360171169Smlaier		kev.filter = EVFILT_SIGNAL;
361171169Smlaier		kev.flags = EV_DELETE;
362171169Smlaier
363171169Smlaier		if (kq_insert(kqop, &kev) == -1)
364171169Smlaier			return (-1);
365171169Smlaier
366171169Smlaier		if (signal(nsignal, SIG_DFL) == SIG_ERR)
367171169Smlaier			return (-1);
368171169Smlaier
369171169Smlaier		ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
370171169Smlaier		return (0);
371171169Smlaier	}
372171169Smlaier
373171169Smlaier	if (ev->ev_events & EV_READ) {
374171169Smlaier 		memset(&kev, 0, sizeof(kev));
375171169Smlaier		kev.ident = ev->ev_fd;
376171169Smlaier		kev.filter = EVFILT_READ;
377171169Smlaier		kev.flags = EV_DELETE;
378171169Smlaier
379171169Smlaier		if (kq_insert(kqop, &kev) == -1)
380171169Smlaier			return (-1);
381171169Smlaier
382171169Smlaier		ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
383171169Smlaier	}
384171169Smlaier
385171169Smlaier	if (ev->ev_events & EV_WRITE) {
386171169Smlaier 		memset(&kev, 0, sizeof(kev));
387171169Smlaier		kev.ident = ev->ev_fd;
388171169Smlaier		kev.filter = EVFILT_WRITE;
389171169Smlaier		kev.flags = EV_DELETE;
390171169Smlaier
391171169Smlaier		if (kq_insert(kqop, &kev) == -1)
392171169Smlaier			return (-1);
393171169Smlaier
394171169Smlaier		ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
395171169Smlaier	}
396171169Smlaier
397171169Smlaier	return (0);
398171169Smlaier}
399171169Smlaier
400171169Smlaiervoid
401171169Smlaierkq_dealloc(void *arg)
402171169Smlaier{
403171169Smlaier	struct kqop *kqop = arg;
404171169Smlaier
405171169Smlaier	if (kqop->changes)
406171169Smlaier		free(kqop->changes);
407171169Smlaier	if (kqop->events)
408171169Smlaier		free(kqop->events);
409171169Smlaier	if (kqop->kq)
410171169Smlaier		close(kqop->kq);
411171169Smlaier	memset(kqop, 0, sizeof(struct kqop));
412171169Smlaier	free(kqop);
413171169Smlaier}
414