~ubuntu-branches/ubuntu/warty/libevent/warty

« back to all changes in this revision

Viewing changes to kqueue.c

  • Committer: Bazaar Package Importer
  • Author(s): Simon Law
  • Date: 2004-05-16 15:36:39 UTC
  • Revision ID: james.westby@ubuntu.com-20040516153639-9j1p0j1nei5rz6uv
Tags: upstream-0.8
ImportĀ upstreamĀ versionĀ 0.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*      $OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $  */
 
2
 
 
3
/*
 
4
 * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
 
5
 * All rights reserved.
 
6
 *
 
7
 * Redistribution and use in source and binary forms, with or without
 
8
 * modification, are permitted provided that the following conditions
 
9
 * are met:
 
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.
 
17
 *
 
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.
 
28
 */
 
29
#ifdef HAVE_CONFIG_H
 
30
#include "config.h"
 
31
#endif
 
32
 
 
33
#include <sys/types.h>
 
34
#ifdef HAVE_SYS_TIME_H
 
35
#include <sys/time.h>
 
36
#else
 
37
#include <sys/_time.h>
 
38
#endif
 
39
#include <sys/queue.h>
 
40
#include <sys/event.h>
 
41
#include <signal.h>
 
42
#include <stdio.h>
 
43
#include <stdlib.h>
 
44
#include <string.h>
 
45
#include <unistd.h>
 
46
#include <errno.h>
 
47
#include <err.h>
 
48
#ifdef HAVE_INTTYPES_H
 
49
#include <inttypes.h>
 
50
#endif
 
51
 
 
52
#ifdef USE_LOG
 
53
#include "log.h"
 
54
#else
 
55
#define LOG_DBG(x)
 
56
#define log_error       warn
 
57
#endif
 
58
 
 
59
#if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__)
 
60
#define INTPTR(x)       (intptr_t)x
 
61
#else
 
62
#define INTPTR(x)       x
 
63
#endif
 
64
 
 
65
#include "event.h"
 
66
 
 
67
extern struct event_list timequeue;
 
68
extern struct event_list eventqueue;
 
69
extern struct event_list addqueue;
 
70
 
 
71
#define EVLIST_X_KQINKERNEL     0x1000
 
72
 
 
73
#define NEVENT          64
 
74
 
 
75
struct kqop {
 
76
        struct kevent *changes;
 
77
        int nchanges;
 
78
        struct kevent *events;
 
79
        int nevents;
 
80
        int kq;
 
81
} kqueueop;
 
82
 
 
83
void *kq_init   (void);
 
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 *);
 
89
 
 
90
const struct eventop kqops = {
 
91
        "kqueue",
 
92
        kq_init,
 
93
        kq_add,
 
94
        kq_del,
 
95
        kq_recalc,
 
96
        kq_dispatch
 
97
};
 
98
 
 
99
void *
 
100
kq_init(void)
 
101
{
 
102
        int kq;
 
103
 
 
104
        /* Disable kqueue when this environment variable is set */
 
105
        if (getenv("EVENT_NOKQUEUE"))
 
106
                return (NULL);
 
107
 
 
108
        memset(&kqueueop, 0, sizeof(kqueueop));
 
109
 
 
110
        /* Initalize the kernel queue */
 
111
        
 
112
        if ((kq = kqueue()) == -1) {
 
113
                log_error("kqueue");
 
114
                return (NULL);
 
115
        }
 
116
 
 
117
        kqueueop.kq = kq;
 
118
 
 
119
        /* Initalize fields */
 
120
        kqueueop.changes = malloc(NEVENT * sizeof(struct kevent));
 
121
        if (kqueueop.changes == NULL)
 
122
                return (NULL);
 
123
        kqueueop.events = malloc(NEVENT * sizeof(struct kevent));
 
124
        if (kqueueop.events == NULL) {
 
125
                free (kqueueop.changes);
 
126
                return (NULL);
 
127
        }
 
128
        kqueueop.nevents = NEVENT;
 
129
 
 
130
        return (&kqueueop);
 
131
}
 
132
 
 
133
int
 
134
kq_recalc(void *arg, int max)
 
135
{
 
136
        return (0);
 
137
}
 
138
 
 
139
int
 
140
kq_insert(struct kqop *kqop, struct kevent *kev)
 
141
{
 
142
        int nevents = kqop->nevents;
 
143
 
 
144
        if (kqop->nchanges == nevents) {
 
145
                struct kevent *newchange;
 
146
                struct kevent *newresult;
 
147
 
 
148
                nevents *= 2;
 
149
 
 
150
                newchange = realloc(kqop->changes,
 
151
                                    nevents * sizeof(struct kevent));
 
152
                if (newchange == NULL) {
 
153
                        log_error("%s: malloc", __func__);
 
154
                        return (-1);
 
155
                }
 
156
                kqop->changes = newchange;
 
157
 
 
158
                newresult = realloc(kqop->events,
 
159
                                    nevents * sizeof(struct kevent));
 
160
 
 
161
                /*
 
162
                 * If we fail, we don't have to worry about freeing,
 
163
                 * the next realloc will pick it up.
 
164
                 */
 
165
                if (newresult == NULL) {
 
166
                        log_error("%s: malloc", __func__);
 
167
                        return (-1);
 
168
                }
 
169
                kqop->events = newresult;
 
170
 
 
171
                kqop->nevents = nevents;
 
172
        }
 
173
 
 
174
        memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
 
175
 
 
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)" : ""));
 
180
 
 
181
        return (0);
 
182
}
 
183
 
 
184
static void
 
185
kq_sighandler(int sig)
 
186
{
 
187
        /* Do nothing here */
 
188
}
 
189
 
 
190
int
 
191
kq_dispatch(void *arg, struct timeval *tv)
 
192
{
 
193
        struct kqop *kqop = arg;
 
194
        struct kevent *changes = kqop->changes;
 
195
        struct kevent *events = kqop->events;
 
196
        struct event *ev;
 
197
        struct timespec ts;
 
198
        int i, res;
 
199
 
 
200
        TIMEVAL_TO_TIMESPEC(tv, &ts);
 
201
 
 
202
        res = kevent(kqop->kq, changes, kqop->nchanges,
 
203
            events, kqop->nevents, &ts);
 
204
        kqop->nchanges = 0;
 
205
        if (res == -1) {
 
206
                if (errno != EINTR) {
 
207
                        log_error("kevent");
 
208
                        return (-1);
 
209
                }
 
210
 
 
211
                return (0);
 
212
        }
 
213
 
 
214
        LOG_DBG((LOG_MISC, 80, "%s: kevent reports %d", __func__, res));
 
215
 
 
216
        for (i = 0; i < res; i++) {
 
217
                int which = 0;
 
218
 
 
219
                if (events[i].flags & EV_ERROR) {
 
220
                        /* 
 
221
                         * Error messages that can happen, when a delete fails.
 
222
                         *   EBADF happens when the file discriptor has been
 
223
                         *   closed,
 
224
                         *   ENOENT when the file discriptor was closed and
 
225
                         *   then reopened.
 
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.
 
229
                         */
 
230
                        if (events[i].data == EBADF ||
 
231
                            events[i].data == ENOENT)
 
232
                                continue;
 
233
                        return (-1);
 
234
                }
 
235
 
 
236
                ev = (struct event *)events[i].udata;
 
237
 
 
238
                if (events[i].filter == EVFILT_READ) {
 
239
                        which |= EV_READ;
 
240
                } else if (events[i].filter == EVFILT_WRITE) {
 
241
                        which |= EV_WRITE;
 
242
                } else if (events[i].filter == EVFILT_SIGNAL) {
 
243
                        which |= EV_SIGNAL;
 
244
                }
 
245
 
 
246
                if (!which)
 
247
                        continue;
 
248
 
 
249
                if (!(ev->ev_events & EV_PERSIST)) {
 
250
                        ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
 
251
                        event_del(ev);
 
252
                }
 
253
 
 
254
                event_active(ev, which,
 
255
                    ev->ev_events & EV_SIGNAL ? events[i].data : 1);
 
256
        }
 
257
 
 
258
        return (0);
 
259
}
 
260
 
 
261
 
 
262
int
 
263
kq_add(void *arg, struct event *ev)
 
264
{
 
265
        struct kqop *kqop = arg;
 
266
        struct kevent kev;
 
267
 
 
268
        if (ev->ev_events & EV_SIGNAL) {
 
269
                int nsignal = EVENT_SIGNAL(ev);
 
270
 
 
271
                memset(&kev, 0, sizeof(kev));
 
272
                kev.ident = nsignal;
 
273
                kev.filter = EVFILT_SIGNAL;
 
274
                kev.flags = EV_ADD;
 
275
                if (!(ev->ev_events & EV_PERSIST))
 
276
                        kev.flags |= EV_ONESHOT;
 
277
                kev.udata = INTPTR(ev);
 
278
                
 
279
                if (kq_insert(kqop, &kev) == -1)
 
280
                        return (-1);
 
281
 
 
282
                if (signal(nsignal, kq_sighandler) == SIG_ERR)
 
283
                        return (-1);
 
284
 
 
285
                ev->ev_flags |= EVLIST_X_KQINKERNEL;
 
286
                return (0);
 
287
        }
 
288
 
 
289
        if (ev->ev_events & EV_READ) {
 
290
                memset(&kev, 0, sizeof(kev));
 
291
                kev.ident = ev->ev_fd;
 
292
                kev.filter = EVFILT_READ;
 
293
#ifdef NOTE_EOF
 
294
                /* Make it behave like select() and poll() */
 
295
                kev.fflags = NOTE_EOF;
 
296
#endif
 
297
                kev.flags = EV_ADD;
 
298
                if (!(ev->ev_events & EV_PERSIST))
 
299
                        kev.flags |= EV_ONESHOT;
 
300
                kev.udata = INTPTR(ev);
 
301
                
 
302
                if (kq_insert(kqop, &kev) == -1)
 
303
                        return (-1);
 
304
 
 
305
                ev->ev_flags |= EVLIST_X_KQINKERNEL;
 
306
        }
 
307
 
 
308
        if (ev->ev_events & EV_WRITE) {
 
309
                memset(&kev, 0, sizeof(kev));
 
310
                kev.ident = ev->ev_fd;
 
311
                kev.filter = EVFILT_WRITE;
 
312
                kev.flags = EV_ADD;
 
313
                if (!(ev->ev_events & EV_PERSIST))
 
314
                        kev.flags |= EV_ONESHOT;
 
315
                kev.udata = INTPTR(ev);
 
316
                
 
317
                if (kq_insert(kqop, &kev) == -1)
 
318
                        return (-1);
 
319
 
 
320
                ev->ev_flags |= EVLIST_X_KQINKERNEL;
 
321
        }
 
322
 
 
323
        return (0);
 
324
}
 
325
 
 
326
int
 
327
kq_del(void *arg, struct event *ev)
 
328
{
 
329
        struct kqop *kqop = arg;
 
330
        struct kevent kev;
 
331
 
 
332
        if (!(ev->ev_flags & EVLIST_X_KQINKERNEL))
 
333
                return (0);
 
334
 
 
335
        if (ev->ev_events & EV_SIGNAL) {
 
336
                int nsignal = EVENT_SIGNAL(ev);
 
337
 
 
338
                memset(&kev, 0, sizeof(kev));
 
339
                kev.ident = (int)signal;
 
340
                kev.filter = EVFILT_SIGNAL;
 
341
                kev.flags = EV_DELETE;
 
342
                
 
343
                if (kq_insert(kqop, &kev) == -1)
 
344
                        return (-1);
 
345
 
 
346
                if (signal(nsignal, SIG_DFL) == SIG_ERR)
 
347
                        return (-1);
 
348
 
 
349
                ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
 
350
                return (0);
 
351
        }
 
352
 
 
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;
 
358
                
 
359
                if (kq_insert(kqop, &kev) == -1)
 
360
                        return (-1);
 
361
 
 
362
                ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
 
363
        }
 
364
 
 
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;
 
370
                
 
371
                if (kq_insert(kqop, &kev) == -1)
 
372
                        return (-1);
 
373
 
 
374
                ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
 
375
        }
 
376
 
 
377
        return (0);
 
378
}