xref: /openbsd/lib/libevent/kqueue.c (revision 4643be29)
1*4643be29Sbrad /*	$OpenBSD: kqueue.c,v 1.15 2005/04/22 00:56:25 brad Exp $	*/
234fc9cdeSmickey 
3fd332320Sprovos /*
4fd332320Sprovos  * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
5fd332320Sprovos  * All rights reserved.
6fd332320Sprovos  *
7fd332320Sprovos  * Redistribution and use in source and binary forms, with or without
8fd332320Sprovos  * modification, are permitted provided that the following conditions
9fd332320Sprovos  * are met:
10fd332320Sprovos  * 1. Redistributions of source code must retain the above copyright
11fd332320Sprovos  *    notice, this list of conditions and the following disclaimer.
12fd332320Sprovos  * 2. Redistributions in binary form must reproduce the above copyright
13fd332320Sprovos  *    notice, this list of conditions and the following disclaimer in the
14fd332320Sprovos  *    documentation and/or other materials provided with the distribution.
15ff9272daSbrad  * 3. The name of the author may not be used to endorse or promote products
16fd332320Sprovos  *    derived from this software without specific prior written permission.
17fd332320Sprovos  *
18fd332320Sprovos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19fd332320Sprovos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20fd332320Sprovos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21fd332320Sprovos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22fd332320Sprovos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23fd332320Sprovos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24fd332320Sprovos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25fd332320Sprovos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26fd332320Sprovos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27fd332320Sprovos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28fd332320Sprovos  */
291770acb2Smarkus #ifdef HAVE_CONFIG_H
30fd332320Sprovos #include "config.h"
311770acb2Smarkus #endif
32fd332320Sprovos 
33fd332320Sprovos #include <sys/types.h>
341770acb2Smarkus #ifdef HAVE_SYS_TIME_H
35fd332320Sprovos #include <sys/time.h>
361770acb2Smarkus #else
371770acb2Smarkus #include <sys/_time.h>
381770acb2Smarkus #endif
39fd332320Sprovos #include <sys/queue.h>
40fd332320Sprovos #include <sys/event.h>
41fd332320Sprovos #include <signal.h>
42fd332320Sprovos #include <stdio.h>
43fd332320Sprovos #include <stdlib.h>
44ff33a3f0Sderaadt #include <string.h>
45fd332320Sprovos #include <unistd.h>
46fd332320Sprovos #include <errno.h>
471770acb2Smarkus #ifdef HAVE_INTTYPES_H
481770acb2Smarkus #include <inttypes.h>
491770acb2Smarkus #endif
50fd332320Sprovos 
51*4643be29Sbrad #if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__)
521770acb2Smarkus #define INTPTR(x)	(intptr_t)x
531770acb2Smarkus #else
541770acb2Smarkus #define INTPTR(x)	x
55fd332320Sprovos #endif
56fd332320Sprovos 
57fd332320Sprovos #include "event.h"
58*4643be29Sbrad #include "log.h"
59fd332320Sprovos 
60fd332320Sprovos #define EVLIST_X_KQINKERNEL	0x1000
61fd332320Sprovos 
62fd332320Sprovos #define NEVENT		64
63fd332320Sprovos 
64fd332320Sprovos struct kqop {
65fd332320Sprovos 	struct kevent *changes;
66fd332320Sprovos 	int nchanges;
67fd332320Sprovos 	struct kevent *events;
68fd332320Sprovos 	int nevents;
69fd332320Sprovos 	int kq;
70*4643be29Sbrad };
71fd332320Sprovos 
72fd332320Sprovos void *kq_init	(void);
73fd332320Sprovos int kq_add	(void *, struct event *);
74fd332320Sprovos int kq_del	(void *, struct event *);
75*4643be29Sbrad int kq_recalc	(struct event_base *, void *, int);
76*4643be29Sbrad int kq_dispatch	(struct event_base *, void *, struct timeval *);
77ff9272daSbrad int kq_insert	(struct kqop *, struct kevent *);
78fd332320Sprovos 
79759b8817Smickey const struct eventop kqops = {
80fd332320Sprovos 	"kqueue",
81fd332320Sprovos 	kq_init,
82fd332320Sprovos 	kq_add,
83fd332320Sprovos 	kq_del,
84fd332320Sprovos 	kq_recalc,
85fd332320Sprovos 	kq_dispatch
86fd332320Sprovos };
87fd332320Sprovos 
88fd332320Sprovos void *
89fd332320Sprovos kq_init(void)
90fd332320Sprovos {
91fd332320Sprovos 	int kq;
92*4643be29Sbrad 	struct kqop *kqueueop;
93fd332320Sprovos 
94fd332320Sprovos 	/* Disable kqueue when this environment variable is set */
951770acb2Smarkus 	if (!issetugid() && getenv("EVENT_NOKQUEUE"))
96fd332320Sprovos 		return (NULL);
97fd332320Sprovos 
98*4643be29Sbrad 	if (!(kqueueop = calloc(1, sizeof(struct kqop))))
99*4643be29Sbrad 		return (NULL);
100fd332320Sprovos 
101ff9272daSbrad 	/* Initalize the kernel queue */
102fd332320Sprovos 
103fd332320Sprovos 	if ((kq = kqueue()) == -1) {
104*4643be29Sbrad 		event_warn("kqueue");
105*4643be29Sbrad 		free (kqueueop);
106fd332320Sprovos 		return (NULL);
107fd332320Sprovos 	}
108fd332320Sprovos 
109*4643be29Sbrad 	kqueueop->kq = kq;
110fd332320Sprovos 
111ff9272daSbrad 	/* Initalize fields */
112*4643be29Sbrad 	kqueueop->changes = malloc(NEVENT * sizeof(struct kevent));
113*4643be29Sbrad 	if (kqueueop->changes == NULL) {
114*4643be29Sbrad 		free (kqueueop);
115fd332320Sprovos 		return (NULL);
116fd332320Sprovos 	}
117*4643be29Sbrad 	kqueueop->events = malloc(NEVENT * sizeof(struct kevent));
118*4643be29Sbrad 	if (kqueueop->events == NULL) {
119*4643be29Sbrad 		free (kqueueop->changes);
120*4643be29Sbrad 		free (kqueueop);
121*4643be29Sbrad 		return (NULL);
122*4643be29Sbrad 	}
123*4643be29Sbrad 	kqueueop->nevents = NEVENT;
124fd332320Sprovos 
125*4643be29Sbrad 	return (kqueueop);
126fd332320Sprovos }
127fd332320Sprovos 
128fd332320Sprovos int
129*4643be29Sbrad kq_recalc(struct event_base *base, void *arg, int max)
130fd332320Sprovos {
131fd332320Sprovos 	return (0);
132fd332320Sprovos }
133fd332320Sprovos 
134fd332320Sprovos int
135fd332320Sprovos kq_insert(struct kqop *kqop, struct kevent *kev)
136fd332320Sprovos {
137fd332320Sprovos 	int nevents = kqop->nevents;
138fd332320Sprovos 
139fd332320Sprovos 	if (kqop->nchanges == nevents) {
140fd332320Sprovos 		struct kevent *newchange;
141fd332320Sprovos 		struct kevent *newresult;
142fd332320Sprovos 
143fd332320Sprovos 		nevents *= 2;
144fd332320Sprovos 
145fd332320Sprovos 		newchange = realloc(kqop->changes,
146fd332320Sprovos 				    nevents * sizeof(struct kevent));
147fd332320Sprovos 		if (newchange == NULL) {
148*4643be29Sbrad 			event_warn("%s: malloc", __func__);
149fd332320Sprovos 			return (-1);
150fd332320Sprovos 		}
151fd332320Sprovos 		kqop->changes = newchange;
152fd332320Sprovos 
153ff9272daSbrad 		newresult = realloc(kqop->events,
154fd332320Sprovos 				    nevents * sizeof(struct kevent));
155fd332320Sprovos 
156fd332320Sprovos 		/*
157fd332320Sprovos 		 * If we fail, we don't have to worry about freeing,
158fd332320Sprovos 		 * the next realloc will pick it up.
159fd332320Sprovos 		 */
160fd332320Sprovos 		if (newresult == NULL) {
161*4643be29Sbrad 			event_warn("%s: malloc", __func__);
162fd332320Sprovos 			return (-1);
163fd332320Sprovos 		}
164ff9272daSbrad 		kqop->events = newresult;
165fd332320Sprovos 
166fd332320Sprovos 		kqop->nevents = nevents;
167fd332320Sprovos 	}
168fd332320Sprovos 
169fd332320Sprovos 	memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
170fd332320Sprovos 
171*4643be29Sbrad 	event_debug(("%s: fd %d %s%s",
1721770acb2Smarkus 		 __func__, kev->ident,
173fd332320Sprovos 		 kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
174fd332320Sprovos 		 kev->flags == EV_DELETE ? " (del)" : ""));
175fd332320Sprovos 
176fd332320Sprovos 	return (0);
177fd332320Sprovos }
178fd332320Sprovos 
179fd332320Sprovos static void
180fd332320Sprovos kq_sighandler(int sig)
181fd332320Sprovos {
182fd332320Sprovos 	/* Do nothing here */
183fd332320Sprovos }
184fd332320Sprovos 
185fd332320Sprovos int
186*4643be29Sbrad kq_dispatch(struct event_base *base, void *arg, struct timeval *tv)
187fd332320Sprovos {
188fd332320Sprovos 	struct kqop *kqop = arg;
189fd332320Sprovos 	struct kevent *changes = kqop->changes;
190fd332320Sprovos 	struct kevent *events = kqop->events;
191fd332320Sprovos 	struct event *ev;
192fd332320Sprovos 	struct timespec ts;
193fd332320Sprovos 	int i, res;
194fd332320Sprovos 
195fd332320Sprovos 	TIMEVAL_TO_TIMESPEC(tv, &ts);
196fd332320Sprovos 
197fd332320Sprovos 	res = kevent(kqop->kq, changes, kqop->nchanges,
198fd332320Sprovos 	    events, kqop->nevents, &ts);
199fd332320Sprovos 	kqop->nchanges = 0;
200fd332320Sprovos 	if (res == -1) {
201fd332320Sprovos 		if (errno != EINTR) {
202*4643be29Sbrad                         event_warn("kevent");
203fd332320Sprovos 			return (-1);
204fd332320Sprovos 		}
205fd332320Sprovos 
206fd332320Sprovos 		return (0);
207fd332320Sprovos 	}
208fd332320Sprovos 
209*4643be29Sbrad 	event_debug(("%s: kevent reports %d", __func__, res));
210fd332320Sprovos 
211fd332320Sprovos 	for (i = 0; i < res; i++) {
212fd332320Sprovos 		int which = 0;
213fd332320Sprovos 
214fd332320Sprovos 		if (events[i].flags & EV_ERROR) {
215fd332320Sprovos 			/*
216fd332320Sprovos 			 * Error messages that can happen, when a delete fails.
217fd332320Sprovos 			 *   EBADF happens when the file discriptor has been
218fd332320Sprovos 			 *   closed,
219fd332320Sprovos 			 *   ENOENT when the file discriptor was closed and
220fd332320Sprovos 			 *   then reopened.
221fd332320Sprovos 			 * An error is also indicated when a callback deletes
222fd332320Sprovos 			 * an event we are still processing.  In that case
223fd332320Sprovos 			 * the data field is set to ENOENT.
224fd332320Sprovos 			 */
225fd332320Sprovos 			if (events[i].data == EBADF ||
226fd332320Sprovos 			    events[i].data == ENOENT)
227fd332320Sprovos 				continue;
228fd332320Sprovos 			return (-1);
229fd332320Sprovos 		}
230fd332320Sprovos 
2311770acb2Smarkus 		ev = (struct event *)events[i].udata;
232fd332320Sprovos 
233fd332320Sprovos 		if (events[i].filter == EVFILT_READ) {
234fd332320Sprovos 			which |= EV_READ;
235fd332320Sprovos 		} else if (events[i].filter == EVFILT_WRITE) {
236fd332320Sprovos 			which |= EV_WRITE;
237fd332320Sprovos 		} else if (events[i].filter == EVFILT_SIGNAL) {
238fd332320Sprovos 			which |= EV_SIGNAL;
2391770acb2Smarkus 		}
240fd332320Sprovos 
241fd332320Sprovos 		if (!which)
242fd332320Sprovos 			continue;
243fd332320Sprovos 
2441770acb2Smarkus 		if (!(ev->ev_events & EV_PERSIST)) {
245fd332320Sprovos 			ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
246fd332320Sprovos 			event_del(ev);
2471770acb2Smarkus 		}
248fd332320Sprovos 
2491770acb2Smarkus 		event_active(ev, which,
2501770acb2Smarkus 		    ev->ev_events & EV_SIGNAL ? events[i].data : 1);
251fd332320Sprovos 	}
252fd332320Sprovos 
253fd332320Sprovos 	return (0);
254fd332320Sprovos }
255fd332320Sprovos 
256fd332320Sprovos 
257fd332320Sprovos int
258fd332320Sprovos kq_add(void *arg, struct event *ev)
259fd332320Sprovos {
260fd332320Sprovos 	struct kqop *kqop = arg;
261fd332320Sprovos 	struct kevent kev;
262fd332320Sprovos 
263fd332320Sprovos 	if (ev->ev_events & EV_SIGNAL) {
264fd332320Sprovos 		int nsignal = EVENT_SIGNAL(ev);
265fd332320Sprovos 
266fd332320Sprovos  		memset(&kev, 0, sizeof(kev));
267fd332320Sprovos 		kev.ident = nsignal;
268fd332320Sprovos 		kev.filter = EVFILT_SIGNAL;
269fd332320Sprovos 		kev.flags = EV_ADD;
270fd332320Sprovos 		if (!(ev->ev_events & EV_PERSIST))
271ddb00dd9Sitojun 			kev.flags |= EV_ONESHOT;
2721770acb2Smarkus 		kev.udata = INTPTR(ev);
273fd332320Sprovos 
274fd332320Sprovos 		if (kq_insert(kqop, &kev) == -1)
275fd332320Sprovos 			return (-1);
276fd332320Sprovos 
277fd332320Sprovos 		if (signal(nsignal, kq_sighandler) == SIG_ERR)
278fd332320Sprovos 			return (-1);
279fd332320Sprovos 
280fd332320Sprovos 		ev->ev_flags |= EVLIST_X_KQINKERNEL;
281fd332320Sprovos 		return (0);
282fd332320Sprovos 	}
283fd332320Sprovos 
284fd332320Sprovos 	if (ev->ev_events & EV_READ) {
285fd332320Sprovos  		memset(&kev, 0, sizeof(kev));
286fd332320Sprovos 		kev.ident = ev->ev_fd;
287fd332320Sprovos 		kev.filter = EVFILT_READ;
288ff9272daSbrad #ifdef NOTE_EOF
289c74e3f8eSmarkus 		/* Make it behave like select() and poll() */
290c74e3f8eSmarkus 		kev.fflags = NOTE_EOF;
291ff9272daSbrad #endif
292ff9272daSbrad 		kev.flags = EV_ADD;
293e5c7daabSart 		if (!(ev->ev_events & EV_PERSIST))
294ddb00dd9Sitojun 			kev.flags |= EV_ONESHOT;
2951770acb2Smarkus 		kev.udata = INTPTR(ev);
296fd332320Sprovos 
297fd332320Sprovos 		if (kq_insert(kqop, &kev) == -1)
298fd332320Sprovos 			return (-1);
299fd332320Sprovos 
300fd332320Sprovos 		ev->ev_flags |= EVLIST_X_KQINKERNEL;
301fd332320Sprovos 	}
302fd332320Sprovos 
303fd332320Sprovos 	if (ev->ev_events & EV_WRITE) {
304fd332320Sprovos  		memset(&kev, 0, sizeof(kev));
305fd332320Sprovos 		kev.ident = ev->ev_fd;
306fd332320Sprovos 		kev.filter = EVFILT_WRITE;
307e5c7daabSart 		kev.flags = EV_ADD;
308e5c7daabSart 		if (!(ev->ev_events & EV_PERSIST))
309ddb00dd9Sitojun 			kev.flags |= EV_ONESHOT;
3101770acb2Smarkus 		kev.udata = INTPTR(ev);
311fd332320Sprovos 
312fd332320Sprovos 		if (kq_insert(kqop, &kev) == -1)
313fd332320Sprovos 			return (-1);
314fd332320Sprovos 
315fd332320Sprovos 		ev->ev_flags |= EVLIST_X_KQINKERNEL;
316fd332320Sprovos 	}
317fd332320Sprovos 
318fd332320Sprovos 	return (0);
319fd332320Sprovos }
320fd332320Sprovos 
321fd332320Sprovos int
322fd332320Sprovos kq_del(void *arg, struct event *ev)
323fd332320Sprovos {
324fd332320Sprovos 	struct kqop *kqop = arg;
325fd332320Sprovos 	struct kevent kev;
326fd332320Sprovos 
327fd332320Sprovos 	if (!(ev->ev_flags & EVLIST_X_KQINKERNEL))
328fd332320Sprovos 		return (0);
329fd332320Sprovos 
330fd332320Sprovos 	if (ev->ev_events & EV_SIGNAL) {
331fd332320Sprovos 		int nsignal = EVENT_SIGNAL(ev);
332fd332320Sprovos 
333fd332320Sprovos  		memset(&kev, 0, sizeof(kev));
334fd332320Sprovos 		kev.ident = (int)signal;
335fd332320Sprovos 		kev.filter = EVFILT_SIGNAL;
336fd332320Sprovos 		kev.flags = EV_DELETE;
337fd332320Sprovos 
338fd332320Sprovos 		if (kq_insert(kqop, &kev) == -1)
339fd332320Sprovos 			return (-1);
340fd332320Sprovos 
341fd332320Sprovos 		if (signal(nsignal, SIG_DFL) == SIG_ERR)
342fd332320Sprovos 			return (-1);
343fd332320Sprovos 
344fd332320Sprovos 		ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
345fd332320Sprovos 		return (0);
346fd332320Sprovos 	}
347fd332320Sprovos 
348fd332320Sprovos 	if (ev->ev_events & EV_READ) {
349fd332320Sprovos  		memset(&kev, 0, sizeof(kev));
350fd332320Sprovos 		kev.ident = ev->ev_fd;
351fd332320Sprovos 		kev.filter = EVFILT_READ;
352fd332320Sprovos 		kev.flags = EV_DELETE;
353fd332320Sprovos 
354fd332320Sprovos 		if (kq_insert(kqop, &kev) == -1)
355fd332320Sprovos 			return (-1);
356fd332320Sprovos 
357fd332320Sprovos 		ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
358fd332320Sprovos 	}
359fd332320Sprovos 
360fd332320Sprovos 	if (ev->ev_events & EV_WRITE) {
361fd332320Sprovos  		memset(&kev, 0, sizeof(kev));
362fd332320Sprovos 		kev.ident = ev->ev_fd;
363fd332320Sprovos 		kev.filter = EVFILT_WRITE;
364fd332320Sprovos 		kev.flags = EV_DELETE;
365fd332320Sprovos 
366fd332320Sprovos 		if (kq_insert(kqop, &kev) == -1)
367fd332320Sprovos 			return (-1);
368fd332320Sprovos 
369fd332320Sprovos 		ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
370fd332320Sprovos 	}
371fd332320Sprovos 
372fd332320Sprovos 	return (0);
373fd332320Sprovos }
374