1 /* $OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $ */
4 * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/types.h>
34 #ifdef HAVE_SYS_TIME_H
37 #include <sys/_time.h>
39 #include <sys/queue.h>
40 #include <sys/event.h>
47 #ifdef HAVE_INTTYPES_H
51 /* Some platforms apparently define the udata field of struct kevent as
52 * ntptr_t, whereas others define it as void*. There doesn't seem to be an
53 * easy way to tell them apart via autoconf, so we need to use OS macros. */
54 #if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__)
55 #define PTR_TO_UDATA(x) ((intptr_t)(x))
57 #define PTR_TO_UDATA(x) (x)
63 #define EVLIST_X_KQINKERNEL 0x1000
68 struct kevent
*changes
;
70 struct kevent
*events
;
75 void *kq_init (struct event_base
*);
76 int kq_add (void *, struct event
*);
77 int kq_del (void *, struct event
*);
78 int kq_recalc (struct event_base
*, void *, int);
79 int kq_dispatch (struct event_base
*, void *, struct timeval
*);
80 int kq_insert (struct kqop
*, struct kevent
*);
81 void kq_dealloc (struct event_base
*, void *);
83 const struct eventop kqops
= {
94 kq_init(struct event_base
*base
)
97 struct kqop
*kqueueop
;
99 /* Disable kqueue when this environment variable is set */
100 if (getenv("EVENT_NOKQUEUE"))
103 if (!(kqueueop
= calloc(1, sizeof(struct kqop
))))
106 /* Initalize the kernel queue */
108 if ((kq
= kqueue()) == -1) {
109 event_warn("kqueue");
116 /* Initalize fields */
117 kqueueop
->changes
= malloc(NEVENT
* sizeof(struct kevent
));
118 if (kqueueop
->changes
== NULL
) {
122 kqueueop
->events
= malloc(NEVENT
* sizeof(struct kevent
));
123 if (kqueueop
->events
== NULL
) {
124 free (kqueueop
->changes
);
128 kqueueop
->nevents
= NEVENT
;
130 /* Check for Mac OS X kqueue bug. */
131 kqueueop
->changes
[0].ident
= -1;
132 kqueueop
->changes
[0].filter
= EVFILT_READ
;
133 kqueueop
->changes
[0].flags
= EV_ADD
;
135 * If kqueue works, then kevent will succeed, and it will
136 * stick an error in events[0]. If kqueue is broken, then
140 kqueueop
->changes
, 1, kqueueop
->events
, NEVENT
, NULL
) != 1 ||
141 kqueueop
->events
[0].ident
!= -1 ||
142 kqueueop
->events
[0].flags
!= EV_ERROR
) {
143 event_warn("%s: detected broken kqueue; not using.", __func__
);
144 free(kqueueop
->changes
);
145 free(kqueueop
->events
);
155 kq_recalc(struct event_base
*base
, void *arg
, int max
)
161 kq_insert(struct kqop
*kqop
, struct kevent
*kev
)
163 int nevents
= kqop
->nevents
;
165 if (kqop
->nchanges
== nevents
) {
166 struct kevent
*newchange
;
167 struct kevent
*newresult
;
171 newchange
= realloc(kqop
->changes
,
172 nevents
* sizeof(struct kevent
));
173 if (newchange
== NULL
) {
174 event_warn("%s: malloc", __func__
);
177 kqop
->changes
= newchange
;
179 newresult
= realloc(kqop
->events
,
180 nevents
* sizeof(struct kevent
));
183 * If we fail, we don't have to worry about freeing,
184 * the next realloc will pick it up.
186 if (newresult
== NULL
) {
187 event_warn("%s: malloc", __func__
);
190 kqop
->events
= newresult
;
192 kqop
->nevents
= nevents
;
195 memcpy(&kqop
->changes
[kqop
->nchanges
++], kev
, sizeof(struct kevent
));
197 event_debug(("%s: fd %d %s%s",
198 __func__
, kev
->ident
,
199 kev
->filter
== EVFILT_READ
? "EVFILT_READ" : "EVFILT_WRITE",
200 kev
->flags
== EV_DELETE
? " (del)" : ""));
206 kq_sighandler(int sig
)
208 /* Do nothing here */
212 kq_dispatch(struct event_base
*base
, void *arg
, struct timeval
*tv
)
214 struct kqop
*kqop
= arg
;
215 struct kevent
*changes
= kqop
->changes
;
216 struct kevent
*events
= kqop
->events
;
218 struct timespec ts
, *ts_p
= NULL
;
222 TIMEVAL_TO_TIMESPEC(tv
, &ts
);
226 res
= kevent(kqop
->kq
, changes
, kqop
->nchanges
,
227 events
, kqop
->nevents
, ts_p
);
230 if (errno
!= EINTR
) {
231 event_warn("kevent");
238 event_debug(("%s: kevent reports %d", __func__
, res
));
240 for (i
= 0; i
< res
; i
++) {
243 if (events
[i
].flags
& EV_ERROR
) {
245 * Error messages that can happen, when a delete fails.
246 * EBADF happens when the file discriptor has been
248 * ENOENT when the file discriptor was closed and
250 * EINVAL for some reasons not understood; EINVAL
251 * should not be returned ever; but FreeBSD does :-\
252 * An error is also indicated when a callback deletes
253 * an event we are still processing. In that case
254 * the data field is set to ENOENT.
256 if (events
[i
].data
== EBADF
||
257 events
[i
].data
== EINVAL
||
258 events
[i
].data
== ENOENT
)
260 errno
= events
[i
].data
;
264 ev
= (struct event
*)events
[i
].udata
;
266 if (events
[i
].filter
== EVFILT_READ
) {
268 } else if (events
[i
].filter
== EVFILT_WRITE
) {
270 } else if (events
[i
].filter
== EVFILT_SIGNAL
) {
277 if (!(ev
->ev_events
& EV_PERSIST
))
280 event_active(ev
, which
,
281 ev
->ev_events
& EV_SIGNAL
? events
[i
].data
: 1);
289 kq_add(void *arg
, struct event
*ev
)
291 struct kqop
*kqop
= arg
;
294 if (ev
->ev_events
& EV_SIGNAL
) {
295 int nsignal
= EVENT_SIGNAL(ev
);
297 memset(&kev
, 0, sizeof(kev
));
299 kev
.filter
= EVFILT_SIGNAL
;
301 if (!(ev
->ev_events
& EV_PERSIST
))
302 kev
.flags
|= EV_ONESHOT
;
303 kev
.udata
= PTR_TO_UDATA(ev
);
305 if (kq_insert(kqop
, &kev
) == -1)
308 if (signal(nsignal
, kq_sighandler
) == SIG_ERR
)
311 ev
->ev_flags
|= EVLIST_X_KQINKERNEL
;
315 if (ev
->ev_events
& EV_READ
) {
316 memset(&kev
, 0, sizeof(kev
));
317 kev
.ident
= ev
->ev_fd
;
318 kev
.filter
= EVFILT_READ
;
320 /* Make it behave like select() and poll() */
321 kev
.fflags
= NOTE_EOF
;
324 if (!(ev
->ev_events
& EV_PERSIST
))
325 kev
.flags
|= EV_ONESHOT
;
326 kev
.udata
= PTR_TO_UDATA(ev
);
328 if (kq_insert(kqop
, &kev
) == -1)
331 ev
->ev_flags
|= EVLIST_X_KQINKERNEL
;
334 if (ev
->ev_events
& EV_WRITE
) {
335 memset(&kev
, 0, sizeof(kev
));
336 kev
.ident
= ev
->ev_fd
;
337 kev
.filter
= EVFILT_WRITE
;
339 if (!(ev
->ev_events
& EV_PERSIST
))
340 kev
.flags
|= EV_ONESHOT
;
341 kev
.udata
= PTR_TO_UDATA(ev
);
343 if (kq_insert(kqop
, &kev
) == -1)
346 ev
->ev_flags
|= EVLIST_X_KQINKERNEL
;
353 kq_del(void *arg
, struct event
*ev
)
355 struct kqop
*kqop
= arg
;
358 if (!(ev
->ev_flags
& EVLIST_X_KQINKERNEL
))
361 if (ev
->ev_events
& EV_SIGNAL
) {
362 int nsignal
= EVENT_SIGNAL(ev
);
364 memset(&kev
, 0, sizeof(kev
));
366 kev
.filter
= EVFILT_SIGNAL
;
367 kev
.flags
= EV_DELETE
;
369 if (kq_insert(kqop
, &kev
) == -1)
372 if (signal(nsignal
, SIG_DFL
) == SIG_ERR
)
375 ev
->ev_flags
&= ~EVLIST_X_KQINKERNEL
;
379 if (ev
->ev_events
& EV_READ
) {
380 memset(&kev
, 0, sizeof(kev
));
381 kev
.ident
= ev
->ev_fd
;
382 kev
.filter
= EVFILT_READ
;
383 kev
.flags
= EV_DELETE
;
385 if (kq_insert(kqop
, &kev
) == -1)
388 ev
->ev_flags
&= ~EVLIST_X_KQINKERNEL
;
391 if (ev
->ev_events
& EV_WRITE
) {
392 memset(&kev
, 0, sizeof(kev
));
393 kev
.ident
= ev
->ev_fd
;
394 kev
.filter
= EVFILT_WRITE
;
395 kev
.flags
= EV_DELETE
;
397 if (kq_insert(kqop
, &kev
) == -1)
400 ev
->ev_flags
&= ~EVLIST_X_KQINKERNEL
;
407 kq_dealloc(struct event_base
*base
, void *arg
)
409 struct kqop
*kqop
= arg
;
417 memset(kqop
, 0, sizeof(struct kqop
));