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 #define PTR_TO_UDATA(x) ((void *)(x))
59 #define EVLIST_X_KQINKERNEL 0x1000
64 struct kevent
*changes
;
66 struct kevent
*events
;
71 void *kq_init (struct event_base
*);
72 int kq_add (void *, struct event
*);
73 int kq_del (void *, struct event
*);
74 int kq_recalc (struct event_base
*, void *, int);
75 int kq_dispatch (struct event_base
*, void *, struct timeval
*);
76 int kq_insert (struct kqop
*, struct kevent
*);
77 void kq_dealloc (struct event_base
*, void *);
79 const struct eventop kqops
= {
90 kq_init(struct event_base
*base
)
93 struct kqop
*kqueueop
;
95 /* Disable kqueue when this environment variable is set */
96 if (getenv("EVENT_NOKQUEUE"))
99 if (!(kqueueop
= calloc(1, sizeof(struct kqop
))))
102 /* Initalize the kernel queue */
104 if ((kq
= kqueue()) == -1) {
105 event_warn("kqueue");
112 /* Initalize fields */
113 kqueueop
->changes
= malloc(NEVENT
* sizeof(struct kevent
));
114 if (kqueueop
->changes
== NULL
) {
118 kqueueop
->events
= malloc(NEVENT
* sizeof(struct kevent
));
119 if (kqueueop
->events
== NULL
) {
120 free (kqueueop
->changes
);
124 kqueueop
->nevents
= NEVENT
;
126 /* Check for Mac OS X kqueue bug. */
127 kqueueop
->changes
[0].ident
= -1;
128 kqueueop
->changes
[0].filter
= EVFILT_READ
;
129 kqueueop
->changes
[0].flags
= EV_ADD
;
131 * If kqueue works, then kevent will succeed, and it will
132 * stick an error in events[0]. If kqueue is broken, then
136 kqueueop
->changes
, 1, kqueueop
->events
, NEVENT
, NULL
) != 1 ||
137 kqueueop
->events
[0].ident
!= -1 ||
138 kqueueop
->events
[0].flags
!= EV_ERROR
) {
139 event_warn("%s: detected broken kqueue; not using.", __func__
);
140 free(kqueueop
->changes
);
141 free(kqueueop
->events
);
151 kq_recalc(struct event_base
*base
, void *arg
, int max
)
157 kq_insert(struct kqop
*kqop
, struct kevent
*kev
)
159 int nevents
= kqop
->nevents
;
161 if (kqop
->nchanges
== nevents
) {
162 struct kevent
*newchange
;
163 struct kevent
*newresult
;
167 newchange
= realloc(kqop
->changes
,
168 nevents
* sizeof(struct kevent
));
169 if (newchange
== NULL
) {
170 event_warn("%s: malloc", __func__
);
173 kqop
->changes
= newchange
;
175 newresult
= realloc(kqop
->events
,
176 nevents
* sizeof(struct kevent
));
179 * If we fail, we don't have to worry about freeing,
180 * the next realloc will pick it up.
182 if (newresult
== NULL
) {
183 event_warn("%s: malloc", __func__
);
186 kqop
->events
= newresult
;
188 kqop
->nevents
= nevents
;
191 memcpy(&kqop
->changes
[kqop
->nchanges
++], kev
, sizeof(struct kevent
));
193 event_debug(("%s: fd %d %s%s",
194 __func__
, kev
->ident
,
195 kev
->filter
== EVFILT_READ
? "EVFILT_READ" : "EVFILT_WRITE",
196 kev
->flags
== EV_DELETE
? " (del)" : ""));
202 kq_sighandler(int sig
)
204 /* Do nothing here */
208 kq_dispatch(struct event_base
*base
, void *arg
, struct timeval
*tv
)
210 struct kqop
*kqop
= arg
;
211 struct kevent
*changes
= kqop
->changes
;
212 struct kevent
*events
= kqop
->events
;
214 struct timespec ts
, *ts_p
= NULL
;
218 TIMEVAL_TO_TIMESPEC(tv
, &ts
);
222 res
= kevent(kqop
->kq
, changes
, kqop
->nchanges
,
223 events
, kqop
->nevents
, ts_p
);
226 if (errno
!= EINTR
) {
227 event_warn("kevent");
234 event_debug(("%s: kevent reports %d", __func__
, res
));
236 for (i
= 0; i
< res
; i
++) {
239 if (events
[i
].flags
& EV_ERROR
) {
241 * Error messages that can happen, when a delete fails.
242 * EBADF happens when the file discriptor has been
244 * ENOENT when the file discriptor was closed and
246 * EINVAL for some reasons not understood; EINVAL
247 * should not be returned ever; but FreeBSD does :-\
248 * An error is also indicated when a callback deletes
249 * an event we are still processing. In that case
250 * the data field is set to ENOENT.
252 if (events
[i
].data
== EBADF
||
253 events
[i
].data
== EINVAL
||
254 events
[i
].data
== ENOENT
)
256 errno
= events
[i
].data
;
260 ev
= (struct event
*)events
[i
].udata
;
262 if (events
[i
].filter
== EVFILT_READ
) {
264 } else if (events
[i
].filter
== EVFILT_WRITE
) {
266 } else if (events
[i
].filter
== EVFILT_SIGNAL
) {
273 if (!(ev
->ev_events
& EV_PERSIST
))
276 event_active(ev
, which
,
277 ev
->ev_events
& EV_SIGNAL
? events
[i
].data
: 1);
285 kq_add(void *arg
, struct event
*ev
)
287 struct kqop
*kqop
= arg
;
290 if (ev
->ev_events
& EV_SIGNAL
) {
291 int nsignal
= EVENT_SIGNAL(ev
);
293 memset(&kev
, 0, sizeof(kev
));
295 kev
.filter
= EVFILT_SIGNAL
;
297 if (!(ev
->ev_events
& EV_PERSIST
))
298 kev
.flags
|= EV_ONESHOT
;
299 kev
.udata
= PTR_TO_UDATA(ev
);
301 if (kq_insert(kqop
, &kev
) == -1)
304 if (signal(nsignal
, kq_sighandler
) == SIG_ERR
)
307 ev
->ev_flags
|= EVLIST_X_KQINKERNEL
;
311 if (ev
->ev_events
& EV_READ
) {
312 memset(&kev
, 0, sizeof(kev
));
313 kev
.ident
= ev
->ev_fd
;
314 kev
.filter
= EVFILT_READ
;
316 /* Make it behave like select() and poll() */
317 kev
.fflags
= NOTE_EOF
;
320 if (!(ev
->ev_events
& EV_PERSIST
))
321 kev
.flags
|= EV_ONESHOT
;
322 kev
.udata
= PTR_TO_UDATA(ev
);
324 if (kq_insert(kqop
, &kev
) == -1)
327 ev
->ev_flags
|= EVLIST_X_KQINKERNEL
;
330 if (ev
->ev_events
& EV_WRITE
) {
331 memset(&kev
, 0, sizeof(kev
));
332 kev
.ident
= ev
->ev_fd
;
333 kev
.filter
= EVFILT_WRITE
;
335 if (!(ev
->ev_events
& EV_PERSIST
))
336 kev
.flags
|= EV_ONESHOT
;
337 kev
.udata
= PTR_TO_UDATA(ev
);
339 if (kq_insert(kqop
, &kev
) == -1)
342 ev
->ev_flags
|= EVLIST_X_KQINKERNEL
;
349 kq_del(void *arg
, struct event
*ev
)
351 struct kqop
*kqop
= arg
;
354 if (!(ev
->ev_flags
& EVLIST_X_KQINKERNEL
))
357 if (ev
->ev_events
& EV_SIGNAL
) {
358 int nsignal
= EVENT_SIGNAL(ev
);
360 memset(&kev
, 0, sizeof(kev
));
362 kev
.filter
= EVFILT_SIGNAL
;
363 kev
.flags
= EV_DELETE
;
365 if (kq_insert(kqop
, &kev
) == -1)
368 if (signal(nsignal
, SIG_DFL
) == SIG_ERR
)
371 ev
->ev_flags
&= ~EVLIST_X_KQINKERNEL
;
375 if (ev
->ev_events
& EV_READ
) {
376 memset(&kev
, 0, sizeof(kev
));
377 kev
.ident
= ev
->ev_fd
;
378 kev
.filter
= EVFILT_READ
;
379 kev
.flags
= EV_DELETE
;
381 if (kq_insert(kqop
, &kev
) == -1)
384 ev
->ev_flags
&= ~EVLIST_X_KQINKERNEL
;
387 if (ev
->ev_events
& EV_WRITE
) {
388 memset(&kev
, 0, sizeof(kev
));
389 kev
.ident
= ev
->ev_fd
;
390 kev
.filter
= EVFILT_WRITE
;
391 kev
.flags
= EV_DELETE
;
393 if (kq_insert(kqop
, &kev
) == -1)
396 ev
->ev_flags
&= ~EVLIST_X_KQINKERNEL
;
403 kq_dealloc(struct event_base
*base
, void *arg
)
405 struct kqop
*kqop
= arg
;
413 memset(kqop
, 0, sizeof(struct kqop
));