ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libev/ev_kqueue.c
Revision: 1.2
Committed: Fri Nov 2 21:17:30 2007 UTC (16 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.1: +10 -24 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1
2     /*
3     * Copyright 2007 Marc Alexander Lehmann <libev@schmorp.de>
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     *
11     * 1. Redistributions of source code must retain the above copyright
12     * notice, this list of conditions and the following disclaimer.
13     * 2. Redistributions in binary form must reproduce the above copyright
14     * notice, this list of conditions and the following disclaimer in the
15     * documentation and/or other materials provided with the distribution.
16     * 3. The name of the author may not be used to endorse or promote products
17     * derived from this software without specific prior written permission.
18     *
19     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20     * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21     * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22     * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23     * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24     * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25     * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26     * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28     * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29     */
30    
31     #include <sys/types.h>
32     #include <sys/time.h>
33     #include <sys/queue.h>
34     #include <sys/event.h>
35     #include <string.h>
36     #include <errno.h>
37    
38     static int kq_fd;
39     static struct kevent *kq_changes;
40     static int kq_changemax, kq_changecnt;
41     static struct kevent *kq_events;
42     static int kq_eventmax;
43    
44     static void
45     kqueue_change (int fd, int filter, int flags, int fflags)
46     {
47     struct kevent *ke;
48    
49     array_needsize (kq_changes, kq_changemax, ++kq_changecnt, );
50    
51     ke = &kq_changes [kq_changecnt - 1];
52     memset (ke, 0, sizeof (struct kevent));
53     ke->ident = fd;
54     ke->filter = filter;
55     ke->flags = flags;
56     ke->fflags = fflags;
57     }
58    
59     static void
60     kqueue_modify (int fd, int oev, int nev)
61     {
62     if ((oev ^ new) & EV_READ)
63     {
64     if (nev & EV_READ)
65     kqueue_change (fd, EVFILT_READ, EV_ADD, NOTE_EOF);
66     else
67     kqueue_change (fd, EVFILT_READ, EV_DELETE, 0);
68     }
69    
70     if ((oev ^ new) & EV_WRITE)
71     {
72     if (nev & EV_WRITE)
73     kqueue_change (fd, EVFILT_WRITE, EV_ADD, NOTE_EOF);
74     else
75     kqueue_change (fd, EVFILT_WRITE, EV_DELETE, 0);
76     }
77     }
78    
79     static void
80     kqueue_poll (ev_tstamp timeout)
81     {
82     int res, i;
83     struct timespec ts;
84    
85     ts.tv_sec = (time_t)timeout;
86     ts.tv_nsec = (long)(timeout - (ev_tstamp)ts.tv_sec) * 1e9;
87     res = kevent (kq_fd, kq_changes, kq_changecnt, kq_events, kq_eventmax, &ts);
88     kq_changecnt = 0;
89    
90     if (res < 0)
91     return;
92    
93     for (i = 0; i < res; ++i)
94     {
95     if (kq_events [i].flags & EV_ERROR)
96     {
97     /*
98     * Error messages that can happen, when a delete fails.
99     * EBADF happens when the file discriptor has been
100     * closed,
101     * ENOENT when the file discriptor was closed and
102     * then reopened.
103     * EINVAL for some reasons not understood; EINVAL
104     * should not be returned ever; but FreeBSD does :-\
105     * An error is also indicated when a callback deletes
106     * an event we are still processing. In that case
107     * the data field is set to ENOENT.
108     */
109     if (events [i].data == EBADF)
110     fd_kill (events [i].ident);
111     }
112     else
113     event (
114     events [i].ident,
115     events [i].filter == EVFILT_READ ? EV_READ
116     : events [i].filter == EVFILT_WRITE ? EV_WRITE
117     : 0
118     );
119     }
120    
121     if (expect_false (res == kq_eventmax))
122     {
123     free (kq_events);
124     kq_eventmax = array_roundsize (kq_events, kq_eventmax << 1);
125     kq_events = malloc (sizeof (struct kevent) * kq_eventmax);
126     }
127     }
128    
129     static void
130     kqueue_init (struct event_base *base)
131     {
132 root 1.2 struct kevent ch, ev;
133    
134 root 1.1 /* Initalize the kernel queue */
135 root 1.2 if ((kq_fd = kqueue ()) < 0)
136 root 1.1 return;
137    
138 root 1.2 /* Check for Mac OS X kqueue bug. */
139     ch.ident = -1;
140     ch.filter = EVFILT_READ;
141     ch.flags = EV_ADD;
142 root 1.1
143     /*
144     * If kqueue works, then kevent will succeed, and it will
145     * stick an error in events[0]. If kqueue is broken, then
146     * kevent will fail.
147     */
148 root 1.2 if (kevent (kq_fd, &ch, 1, &ev, 1, 0) != 1
149     || ev.ident != -1
150     || ev.flags != EV_ERROR)
151 root 1.1 {
152     /* detected broken kqueue */
153     close (kq_fd);
154     return;
155     }
156    
157     ev_method = EVMETHOD_KQUEUE;
158     method_fudge = 1e-3; /* needed to compensate for kevent returning early */
159     method_modify = kq_modify;
160     method_poll = kq_poll;
161    
162     kq_eventmax = 64; /* intiial number of events receivable per poll */
163     kq_events = malloc (sizeof (struct kevent) * kq_eventmax);
164     }
165