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>
48
#ifdef HAVE_INTTYPES_H
56
#define log_error warn
59
#if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__)
60
#define INTPTR(x) (intptr_t)x
67
extern struct event_list timequeue;
68
extern struct event_list eventqueue;
69
extern struct event_list addqueue;
71
#define EVLIST_X_KQINKERNEL 0x1000
76
struct kevent *changes;
78
struct kevent *events;
84
int kq_add (void *, struct event *);
85
int kq_del (void *, struct event *);
86
int kq_recalc (void *, int);
87
int kq_dispatch (void *, struct timeval *);
88
int kq_insert (struct kqop *, struct kevent *);
90
const struct eventop kqops = {
104
/* Disable kqueue when this environment variable is set */
105
if (getenv("EVENT_NOKQUEUE"))
108
memset(&kqueueop, 0, sizeof(kqueueop));
110
/* Initalize the kernel queue */
112
if ((kq = kqueue()) == -1) {
119
/* Initalize fields */
120
kqueueop.changes = malloc(NEVENT * sizeof(struct kevent));
121
if (kqueueop.changes == NULL)
123
kqueueop.events = malloc(NEVENT * sizeof(struct kevent));
124
if (kqueueop.events == NULL) {
125
free (kqueueop.changes);
128
kqueueop.nevents = NEVENT;
134
kq_recalc(void *arg, int max)
140
kq_insert(struct kqop *kqop, struct kevent *kev)
142
int nevents = kqop->nevents;
144
if (kqop->nchanges == nevents) {
145
struct kevent *newchange;
146
struct kevent *newresult;
150
newchange = realloc(kqop->changes,
151
nevents * sizeof(struct kevent));
152
if (newchange == NULL) {
153
log_error("%s: malloc", __func__);
156
kqop->changes = newchange;
158
newresult = realloc(kqop->events,
159
nevents * sizeof(struct kevent));
162
* If we fail, we don't have to worry about freeing,
163
* the next realloc will pick it up.
165
if (newresult == NULL) {
166
log_error("%s: malloc", __func__);
169
kqop->events = newresult;
171
kqop->nevents = nevents;
174
memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
176
LOG_DBG((LOG_MISC, 70, "%s: fd %d %s%s",
177
__func__, kev->ident,
178
kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
179
kev->flags == EV_DELETE ? " (del)" : ""));
185
kq_sighandler(int sig)
187
/* Do nothing here */
191
kq_dispatch(void *arg, struct timeval *tv)
193
struct kqop *kqop = arg;
194
struct kevent *changes = kqop->changes;
195
struct kevent *events = kqop->events;
200
TIMEVAL_TO_TIMESPEC(tv, &ts);
202
res = kevent(kqop->kq, changes, kqop->nchanges,
203
events, kqop->nevents, &ts);
206
if (errno != EINTR) {
214
LOG_DBG((LOG_MISC, 80, "%s: kevent reports %d", __func__, res));
216
for (i = 0; i < res; i++) {
219
if (events[i].flags & EV_ERROR) {
221
* Error messages that can happen, when a delete fails.
222
* EBADF happens when the file discriptor has been
224
* ENOENT when the file discriptor was closed and
226
* An error is also indicated when a callback deletes
227
* an event we are still processing. In that case
228
* the data field is set to ENOENT.
230
if (events[i].data == EBADF ||
231
events[i].data == ENOENT)
236
ev = (struct event *)events[i].udata;
238
if (events[i].filter == EVFILT_READ) {
240
} else if (events[i].filter == EVFILT_WRITE) {
242
} else if (events[i].filter == EVFILT_SIGNAL) {
249
if (!(ev->ev_events & EV_PERSIST)) {
250
ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
254
event_active(ev, which,
255
ev->ev_events & EV_SIGNAL ? events[i].data : 1);
263
kq_add(void *arg, struct event *ev)
265
struct kqop *kqop = arg;
268
if (ev->ev_events & EV_SIGNAL) {
269
int nsignal = EVENT_SIGNAL(ev);
271
memset(&kev, 0, sizeof(kev));
273
kev.filter = EVFILT_SIGNAL;
275
if (!(ev->ev_events & EV_PERSIST))
276
kev.flags |= EV_ONESHOT;
277
kev.udata = INTPTR(ev);
279
if (kq_insert(kqop, &kev) == -1)
282
if (signal(nsignal, kq_sighandler) == SIG_ERR)
285
ev->ev_flags |= EVLIST_X_KQINKERNEL;
289
if (ev->ev_events & EV_READ) {
290
memset(&kev, 0, sizeof(kev));
291
kev.ident = ev->ev_fd;
292
kev.filter = EVFILT_READ;
294
/* Make it behave like select() and poll() */
295
kev.fflags = NOTE_EOF;
298
if (!(ev->ev_events & EV_PERSIST))
299
kev.flags |= EV_ONESHOT;
300
kev.udata = INTPTR(ev);
302
if (kq_insert(kqop, &kev) == -1)
305
ev->ev_flags |= EVLIST_X_KQINKERNEL;
308
if (ev->ev_events & EV_WRITE) {
309
memset(&kev, 0, sizeof(kev));
310
kev.ident = ev->ev_fd;
311
kev.filter = EVFILT_WRITE;
313
if (!(ev->ev_events & EV_PERSIST))
314
kev.flags |= EV_ONESHOT;
315
kev.udata = INTPTR(ev);
317
if (kq_insert(kqop, &kev) == -1)
320
ev->ev_flags |= EVLIST_X_KQINKERNEL;
327
kq_del(void *arg, struct event *ev)
329
struct kqop *kqop = arg;
332
if (!(ev->ev_flags & EVLIST_X_KQINKERNEL))
335
if (ev->ev_events & EV_SIGNAL) {
336
int nsignal = EVENT_SIGNAL(ev);
338
memset(&kev, 0, sizeof(kev));
339
kev.ident = (int)signal;
340
kev.filter = EVFILT_SIGNAL;
341
kev.flags = EV_DELETE;
343
if (kq_insert(kqop, &kev) == -1)
346
if (signal(nsignal, SIG_DFL) == SIG_ERR)
349
ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
353
if (ev->ev_events & EV_READ) {
354
memset(&kev, 0, sizeof(kev));
355
kev.ident = ev->ev_fd;
356
kev.filter = EVFILT_READ;
357
kev.flags = EV_DELETE;
359
if (kq_insert(kqop, &kev) == -1)
362
ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
365
if (ev->ev_events & EV_WRITE) {
366
memset(&kev, 0, sizeof(kev));
367
kev.ident = ev->ev_fd;
368
kev.filter = EVFILT_WRITE;
369
kev.flags = EV_DELETE;
371
if (kq_insert(kqop, &kev) == -1)
374
ev->ev_flags &= ~EVLIST_X_KQINKERNEL;