xref: /openbsd/lib/libevent/kqueue.c (revision ddb00dd9)
1*ddb00dd9Sitojun /*	$OpenBSD: kqueue.c,v 1.6 2002/09/08 07:52:33 itojun 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.
15fd332320Sprovos  * 3. All advertising materials mentioning features or use of this software
16fd332320Sprovos  *    must display the following acknowledgement:
17fd332320Sprovos  *      This product includes software developed by Niels Provos.
18fd332320Sprovos  * 4. The name of the author may not be used to endorse or promote products
19fd332320Sprovos  *    derived from this software without specific prior written permission.
20fd332320Sprovos  *
21fd332320Sprovos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22fd332320Sprovos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23fd332320Sprovos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24fd332320Sprovos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25fd332320Sprovos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26fd332320Sprovos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27fd332320Sprovos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28fd332320Sprovos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29fd332320Sprovos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30fd332320Sprovos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31fd332320Sprovos  */
32fd332320Sprovos #include "config.h"
33fd332320Sprovos 
34fd332320Sprovos #include <sys/types.h>
35fd332320Sprovos #include <sys/time.h>
36fd332320Sprovos #include <sys/queue.h>
37fd332320Sprovos #include <sys/event.h>
38fd332320Sprovos #include <signal.h>
39fd332320Sprovos #include <stdio.h>
40fd332320Sprovos #include <stdlib.h>
41ff33a3f0Sderaadt #include <string.h>
42fd332320Sprovos #include <unistd.h>
43fd332320Sprovos #include <errno.h>
44fd332320Sprovos 
45fd332320Sprovos #ifdef USE_LOG
46fd332320Sprovos #include "log.h"
47fd332320Sprovos #else
48fd332320Sprovos #define LOG_DBG(x)
49fd332320Sprovos #define log_error(x)	perror(x)
50fd332320Sprovos #endif
51fd332320Sprovos 
52fd332320Sprovos #include "event.h"
53fd332320Sprovos 
54fd332320Sprovos extern struct event_list timequeue;
55fd332320Sprovos extern struct event_list eventqueue;
56fd332320Sprovos extern struct event_list addqueue;
57fd332320Sprovos 
58fd332320Sprovos #define EVLIST_X_KQINKERNEL	0x1000
59fd332320Sprovos 
60fd332320Sprovos #define NEVENT		64
61fd332320Sprovos 
62fd332320Sprovos struct kqop {
63fd332320Sprovos 	struct kevent *changes;
64fd332320Sprovos 	int nchanges;
65fd332320Sprovos 	struct kevent *events;
66fd332320Sprovos 	int nevents;
67fd332320Sprovos 	int kq;
68fd332320Sprovos } kqop;
69fd332320Sprovos 
70fd332320Sprovos void *kq_init	(void);
71fd332320Sprovos int kq_add	(void *, struct event *);
72fd332320Sprovos int kq_del	(void *, struct event *);
73fd332320Sprovos int kq_recalc	(void *, int);
74fd332320Sprovos int kq_dispatch	(void *, struct timeval *);
75fd332320Sprovos 
76fd332320Sprovos struct eventop kqops = {
77fd332320Sprovos 	"kqueue",
78fd332320Sprovos 	kq_init,
79fd332320Sprovos 	kq_add,
80fd332320Sprovos 	kq_del,
81fd332320Sprovos 	kq_recalc,
82fd332320Sprovos 	kq_dispatch
83fd332320Sprovos };
84fd332320Sprovos 
85fd332320Sprovos void *
86fd332320Sprovos kq_init(void)
87fd332320Sprovos {
88fd332320Sprovos 	int kq;
89fd332320Sprovos 
90fd332320Sprovos 	/* Disable kqueue when this environment variable is set */
91fd332320Sprovos 	if (getenv("EVENT_NOKQUEUE"))
92fd332320Sprovos 		return (NULL);
93fd332320Sprovos 
94fd332320Sprovos 	memset(&kqop, 0, sizeof(kqop));
95fd332320Sprovos 
96fd332320Sprovos 	/* Initalize the kernel queue */
97fd332320Sprovos 
98fd332320Sprovos 	if ((kq = kqueue()) == -1) {
99fd332320Sprovos 		log_error("kqueue");
100fd332320Sprovos 		return (NULL);
101fd332320Sprovos 	}
102fd332320Sprovos 
103fd332320Sprovos 	kqop.kq = kq;
104fd332320Sprovos 
105fd332320Sprovos 	/* Initalize fields */
106fd332320Sprovos 	kqop.changes = malloc(NEVENT * sizeof(struct kevent));
107fd332320Sprovos 	if (kqop.changes == NULL)
108fd332320Sprovos 		return (NULL);
109fd332320Sprovos 	kqop.events = malloc(NEVENT * sizeof(struct kevent));
110fd332320Sprovos 	if (kqop.events == NULL) {
111fd332320Sprovos 		free (kqop.changes);
112fd332320Sprovos 		return (NULL);
113fd332320Sprovos 	}
114fd332320Sprovos 	kqop.nevents = NEVENT;
115fd332320Sprovos 
116fd332320Sprovos 	return (&kqop);
117fd332320Sprovos }
118fd332320Sprovos 
119fd332320Sprovos int
120fd332320Sprovos kq_recalc(void *arg, int max)
121fd332320Sprovos {
122fd332320Sprovos 	return (0);
123fd332320Sprovos }
124fd332320Sprovos 
125fd332320Sprovos int
126fd332320Sprovos kq_insert(struct kqop *kqop, struct kevent *kev)
127fd332320Sprovos {
128fd332320Sprovos 	int nevents = kqop->nevents;
129fd332320Sprovos 
130fd332320Sprovos 	if (kqop->nchanges == nevents) {
131fd332320Sprovos 		struct kevent *newchange;
132fd332320Sprovos 		struct kevent *newresult;
133fd332320Sprovos 
134fd332320Sprovos 		nevents *= 2;
135fd332320Sprovos 
136fd332320Sprovos 		newchange = realloc(kqop->changes,
137fd332320Sprovos 				    nevents * sizeof(struct kevent));
138fd332320Sprovos 		if (newchange == NULL) {
139fd332320Sprovos 			log_error(__FUNCTION__": malloc");
140fd332320Sprovos 			return (-1);
141fd332320Sprovos 		}
142fd332320Sprovos 		kqop->changes = newchange;
143fd332320Sprovos 
144fd332320Sprovos 		newresult = realloc(kqop->changes,
145fd332320Sprovos 				    nevents * sizeof(struct kevent));
146fd332320Sprovos 
147fd332320Sprovos 		/*
148fd332320Sprovos 		 * If we fail, we don't have to worry about freeing,
149fd332320Sprovos 		 * the next realloc will pick it up.
150fd332320Sprovos 		 */
151fd332320Sprovos 		if (newresult == NULL) {
152fd332320Sprovos 			log_error(__FUNCTION__": malloc");
153fd332320Sprovos 			return (-1);
154fd332320Sprovos 		}
155fd332320Sprovos 		kqop->events = newchange;
156fd332320Sprovos 
157fd332320Sprovos 		kqop->nevents = nevents;
158fd332320Sprovos 	}
159fd332320Sprovos 
160fd332320Sprovos 	memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
161fd332320Sprovos 
162fd332320Sprovos 	LOG_DBG((LOG_MISC, 70, __FUNCTION__": fd %d %s%s",
163fd332320Sprovos 		 kev->ident,
164fd332320Sprovos 		 kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
165fd332320Sprovos 		 kev->flags == EV_DELETE ? " (del)" : ""));
166fd332320Sprovos 
167fd332320Sprovos 	return (0);
168fd332320Sprovos }
169fd332320Sprovos 
170fd332320Sprovos static void
171fd332320Sprovos kq_sighandler(int sig)
172fd332320Sprovos {
173fd332320Sprovos 	/* Do nothing here */
174fd332320Sprovos }
175fd332320Sprovos 
176fd332320Sprovos int
177fd332320Sprovos kq_dispatch(void *arg, struct timeval *tv)
178fd332320Sprovos {
179fd332320Sprovos 	struct kqop *kqop = arg;
180fd332320Sprovos 	struct kevent *changes = kqop->changes;
181fd332320Sprovos 	struct kevent *events = kqop->events;
182fd332320Sprovos 	struct event *ev;
183fd332320Sprovos 	struct timespec ts;
184fd332320Sprovos 	int i, res;
185fd332320Sprovos 
186fd332320Sprovos 	TIMEVAL_TO_TIMESPEC(tv, &ts);
187fd332320Sprovos 
188fd332320Sprovos 	res = kevent(kqop->kq, changes, kqop->nchanges,
189fd332320Sprovos 		     events, kqop->nevents, &ts);
190fd332320Sprovos 	kqop->nchanges = 0;
191fd332320Sprovos 	if (res == -1) {
192fd332320Sprovos 		if (errno != EINTR) {
193fd332320Sprovos 			log_error("kevent");
194fd332320Sprovos 			return (-1);
195fd332320Sprovos 		}
196fd332320Sprovos 
197fd332320Sprovos 		return (0);
198fd332320Sprovos 	}
199fd332320Sprovos 
200fd332320Sprovos 	LOG_DBG((LOG_MISC, 80, __FUNCTION__": kevent reports %d", res));
201fd332320Sprovos 
202fd332320Sprovos 	for (i = 0; i < res; i++) {
203fd332320Sprovos 		int which = 0;
204fd332320Sprovos 
205fd332320Sprovos 		if (events[i].flags & EV_ERROR) {
206fd332320Sprovos 			/*
207fd332320Sprovos 			 * Error messages that can happen, when a delete fails.
208fd332320Sprovos 			 *   EBADF happens when the file discriptor has been
209fd332320Sprovos 			 *   closed,
210fd332320Sprovos 			 *   ENOENT when the file discriptor was closed and
211fd332320Sprovos 			 *   then reopened.
212fd332320Sprovos 			 * An error is also indicated when a callback deletes
213fd332320Sprovos 			 * an event we are still processing.  In that case
214fd332320Sprovos 			 * the data field is set to ENOENT.
215fd332320Sprovos 			 */
216fd332320Sprovos 			if (events[i].data == EBADF ||
217fd332320Sprovos 			    events[i].data == ENOENT)
218fd332320Sprovos 				continue;
219fd332320Sprovos 			return (-1);
220fd332320Sprovos 		}
221fd332320Sprovos 
222fd332320Sprovos 		ev = events[i].udata;
223fd332320Sprovos 
224fd332320Sprovos 		if (events[i].filter == EVFILT_READ) {
225fd332320Sprovos 			which |= EV_READ;
226fd332320Sprovos 		} else if (events[i].filter == EVFILT_WRITE) {
227fd332320Sprovos 			which |= EV_WRITE;
228fd332320Sprovos 		} else if (events[i].filter == EVFILT_SIGNAL) {
229fd332320Sprovos 			which |= EV_SIGNAL;
230fd332320Sprovos 		} else
231fd332320Sprovos 			events[i].filter = 0;
232fd332320Sprovos 
233fd332320Sprovos 		if (!which)
234fd332320Sprovos 			continue;
235fd332320Sprovos 
236fd332320Sprovos 		event_active(ev, which,
237fd332320Sprovos 		    ev->ev_events & EV_SIGNAL ? events[i].data : 1);
238fd332320Sprovos 	}
239fd332320Sprovos 
240fd332320Sprovos 	for (i = 0; i < res; i++) {
241fd332320Sprovos 		/* XXX */
242a125e45cSprovos 		int ncalls, evres;
243fd332320Sprovos 
244fd332320Sprovos 		if (events[i].flags & EV_ERROR || events[i].filter == NULL)
245fd332320Sprovos 			continue;
246fd332320Sprovos 
247fd332320Sprovos 		ev = events[i].udata;
248fd332320Sprovos 		if (ev->ev_events & EV_PERSIST)
249fd332320Sprovos 			continue;
250fd332320Sprovos 
251fd332320Sprovos 		ncalls = 0;
252fd332320Sprovos 		if (ev->ev_flags & EVLIST_ACTIVE) {
253fd332320Sprovos 			ncalls = ev->ev_ncalls;
254a125e45cSprovos 			evres = ev->ev_res;
255fd332320Sprovos 		}
256fd332320Sprovos 		ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
257fd332320Sprovos 		event_del(ev);
258fd332320Sprovos 
259fd332320Sprovos 		if (ncalls)
260a125e45cSprovos 			event_active(ev, evres, ncalls);
261fd332320Sprovos 	}
262fd332320Sprovos 
263fd332320Sprovos 	return (0);
264fd332320Sprovos }
265fd332320Sprovos 
266fd332320Sprovos 
267fd332320Sprovos int
268fd332320Sprovos kq_add(void *arg, struct event *ev)
269fd332320Sprovos {
270fd332320Sprovos 	struct kqop *kqop = arg;
271fd332320Sprovos 	struct kevent kev;
272fd332320Sprovos 
273fd332320Sprovos 	if (ev->ev_events & EV_SIGNAL) {
274fd332320Sprovos 		int nsignal = EVENT_SIGNAL(ev);
275fd332320Sprovos 
276fd332320Sprovos  		memset(&kev, 0, sizeof(kev));
277fd332320Sprovos 		kev.ident = nsignal;
278fd332320Sprovos 		kev.filter = EVFILT_SIGNAL;
279fd332320Sprovos 		kev.flags = EV_ADD;
280fd332320Sprovos 		if (!(ev->ev_events & EV_PERSIST))
281*ddb00dd9Sitojun 			kev.flags |= EV_ONESHOT;
282fd332320Sprovos 		kev.udata = ev;
283fd332320Sprovos 
284fd332320Sprovos 		if (kq_insert(kqop, &kev) == -1)
285fd332320Sprovos 			return (-1);
286fd332320Sprovos 
287fd332320Sprovos 		if (signal(nsignal, kq_sighandler) == SIG_ERR)
288fd332320Sprovos 			return (-1);
289fd332320Sprovos 
290fd332320Sprovos 		ev->ev_flags |= EVLIST_X_KQINKERNEL;
291fd332320Sprovos 		return (0);
292fd332320Sprovos 	}
293fd332320Sprovos 
294fd332320Sprovos 	if (ev->ev_events & EV_READ) {
295fd332320Sprovos  		memset(&kev, 0, sizeof(kev));
296fd332320Sprovos 		kev.ident = ev->ev_fd;
297fd332320Sprovos 		kev.filter = EVFILT_READ;
298e5c7daabSart 		kev.flags = EV_ADD;
299e5c7daabSart 		if (!(ev->ev_events & EV_PERSIST))
300*ddb00dd9Sitojun 			kev.flags |= EV_ONESHOT;
301fd332320Sprovos 		kev.udata = ev;
302fd332320Sprovos 
303fd332320Sprovos 		if (kq_insert(kqop, &kev) == -1)
304fd332320Sprovos 			return (-1);
305fd332320Sprovos 
306fd332320Sprovos 		ev->ev_flags |= EVLIST_X_KQINKERNEL;
307fd332320Sprovos 	}
308fd332320Sprovos 
309fd332320Sprovos 	if (ev->ev_events & EV_WRITE) {
310fd332320Sprovos  		memset(&kev, 0, sizeof(kev));
311fd332320Sprovos 		kev.ident = ev->ev_fd;
312fd332320Sprovos 		kev.filter = EVFILT_WRITE;
313e5c7daabSart 		kev.flags = EV_ADD;
314e5c7daabSart 		if (!(ev->ev_events & EV_PERSIST))
315*ddb00dd9Sitojun 			kev.flags |= EV_ONESHOT;
316fd332320Sprovos 		kev.udata = ev;
317fd332320Sprovos 
318fd332320Sprovos 		if (kq_insert(kqop, &kev) == -1)
319fd332320Sprovos 			return (-1);
320fd332320Sprovos 
321fd332320Sprovos 		ev->ev_flags |= EVLIST_X_KQINKERNEL;
322fd332320Sprovos 	}
323fd332320Sprovos 
324fd332320Sprovos 	return (0);
325fd332320Sprovos }
326fd332320Sprovos 
327fd332320Sprovos int
328fd332320Sprovos kq_del(void *arg, struct event *ev)
329fd332320Sprovos {
330fd332320Sprovos 	struct kqop *kqop = arg;
331fd332320Sprovos 	struct kevent kev;
332fd332320Sprovos 
333fd332320Sprovos 	if (!(ev->ev_flags & EVLIST_X_KQINKERNEL))
334fd332320Sprovos 		return (0);
335fd332320Sprovos 
336fd332320Sprovos 	if (ev->ev_events & EV_SIGNAL) {
337fd332320Sprovos 		int nsignal = EVENT_SIGNAL(ev);
338fd332320Sprovos 
339fd332320Sprovos  		memset(&kev, 0, sizeof(kev));
340fd332320Sprovos 		kev.ident = (int)signal;
341fd332320Sprovos 		kev.filter = EVFILT_SIGNAL;
342fd332320Sprovos 		kev.flags = EV_DELETE;
343fd332320Sprovos 
344fd332320Sprovos 		if (kq_insert(kqop, &kev) == -1)
345fd332320Sprovos 			return (-1);
346fd332320Sprovos 
347fd332320Sprovos 		if (signal(nsignal, SIG_DFL) == SIG_ERR)
348fd332320Sprovos 			return (-1);
349fd332320Sprovos 
350fd332320Sprovos 		ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
351fd332320Sprovos 		return (0);
352fd332320Sprovos 	}
353fd332320Sprovos 
354fd332320Sprovos 	if (ev->ev_events & EV_READ) {
355fd332320Sprovos  		memset(&kev, 0, sizeof(kev));
356fd332320Sprovos 		kev.ident = ev->ev_fd;
357fd332320Sprovos 		kev.filter = EVFILT_READ;
358fd332320Sprovos 		kev.flags = EV_DELETE;
359fd332320Sprovos 
360fd332320Sprovos 		if (kq_insert(kqop, &kev) == -1)
361fd332320Sprovos 			return (-1);
362fd332320Sprovos 
363fd332320Sprovos 		ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
364fd332320Sprovos 	}
365fd332320Sprovos 
366fd332320Sprovos 	if (ev->ev_events & EV_WRITE) {
367fd332320Sprovos  		memset(&kev, 0, sizeof(kev));
368fd332320Sprovos 		kev.ident = ev->ev_fd;
369fd332320Sprovos 		kev.filter = EVFILT_WRITE;
370fd332320Sprovos 		kev.flags = EV_DELETE;
371fd332320Sprovos 
372fd332320Sprovos 		if (kq_insert(kqop, &kev) == -1)
373fd332320Sprovos 			return (-1);
374fd332320Sprovos 
375fd332320Sprovos 		ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
376fd332320Sprovos 	}
377fd332320Sprovos 
378fd332320Sprovos 	return (0);
379fd332320Sprovos }
380