ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libev/ev_kqueue.c
Revision: 1.6
Committed: Sat Nov 3 21:58:51 2007 UTC (16 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.5: +29 -33 lines
Log Message:
prepare for multiple bases

File Contents

# User Rev Content
1 root 1.1 /*
2     * Copyright 2007 Marc Alexander Lehmann <libev@schmorp.de>
3     * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
4     * All rights reserved.
5     *
6     * Redistribution and use in source and binary forms, with or without
7     * modification, are permitted provided that the following conditions
8     * are met:
9     *
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    
30     #include <sys/types.h>
31     #include <sys/time.h>
32     #include <sys/queue.h>
33     #include <sys/event.h>
34     #include <string.h>
35     #include <errno.h>
36    
37     static void
38 root 1.6 kqueue_change (EV_P_ int fd, int filter, int flags, int fflags)
39 root 1.1 {
40     struct kevent *ke;
41    
42 root 1.6 array_needsize (kqueue_changes, kqueue_changemax, ++kqueue_changecnt, );
43 root 1.1
44 root 1.6 ke = &kqueue_changes [kqueue_changecnt - 1];
45 root 1.1 memset (ke, 0, sizeof (struct kevent));
46     ke->ident = fd;
47     ke->filter = filter;
48     ke->flags = flags;
49     ke->fflags = fflags;
50     }
51    
52 root 1.4 #ifndef NOTE_EOF
53     # define NOTE_EOF 0
54     #endif
55    
56 root 1.1 static void
57 root 1.6 kqueue_modify (EV_P_ int fd, int oev, int nev)
58 root 1.1 {
59 root 1.4 if ((oev ^ nev) & EV_READ)
60 root 1.1 {
61     if (nev & EV_READ)
62     kqueue_change (fd, EVFILT_READ, EV_ADD, NOTE_EOF);
63     else
64     kqueue_change (fd, EVFILT_READ, EV_DELETE, 0);
65     }
66    
67 root 1.4 if ((oev ^ nev) & EV_WRITE)
68 root 1.1 {
69     if (nev & EV_WRITE)
70     kqueue_change (fd, EVFILT_WRITE, EV_ADD, NOTE_EOF);
71     else
72     kqueue_change (fd, EVFILT_WRITE, EV_DELETE, 0);
73     }
74     }
75    
76     static void
77 root 1.6 kqueue_poll (EV_P_ ev_tstamp timeout)
78 root 1.1 {
79     int res, i;
80     struct timespec ts;
81    
82     ts.tv_sec = (time_t)timeout;
83     ts.tv_nsec = (long)(timeout - (ev_tstamp)ts.tv_sec) * 1e9;
84 root 1.6 res = kevent (kqueue_fd, kqueue_changes, kqueue_changecnt, kqueue_events, kqueue_eventmax, &ts);
85     kqueue_changecnt = 0;
86 root 1.1
87     if (res < 0)
88     return;
89    
90     for (i = 0; i < res; ++i)
91     {
92 root 1.6 if (kqueue_events [i].flags & EV_ERROR)
93 root 1.1 {
94     /*
95     * Error messages that can happen, when a delete fails.
96     * EBADF happens when the file discriptor has been
97     * closed,
98     * ENOENT when the file discriptor was closed and
99     * then reopened.
100     * EINVAL for some reasons not understood; EINVAL
101     * should not be returned ever; but FreeBSD does :-\
102     * An error is also indicated when a callback deletes
103     * an event we are still processing. In that case
104     * the data field is set to ENOENT.
105     */
106 root 1.6 if (kqueue_events [i].data == EBADF)
107     fd_kill (EV_A_ kqueue_events [i].ident);
108 root 1.1 }
109     else
110 root 1.3 fd_event (
111 root 1.6 EV_A_
112     kqueue_events [i].ident,
113     kqueue_events [i].filter == EVFILT_READ ? EV_READ
114     : kqueue_events [i].filter == EVFILT_WRITE ? EV_WRITE
115 root 1.1 : 0
116     );
117     }
118    
119 root 1.6 if (expect_false (res == kqueue_eventmax))
120 root 1.1 {
121 root 1.6 free (kqueue_events);
122     kqueue_eventmax = array_roundsize (kqueue_events, kqueue_eventmax << 1);
123     kqueue_events = malloc (sizeof (struct kevent) * kqueue_eventmax);
124 root 1.1 }
125     }
126    
127 root 1.6 static int
128     kqueue_init (EV_P_ int flags)
129 root 1.1 {
130 root 1.2 struct kevent ch, ev;
131    
132 root 1.1 /* Initalize the kernel queue */
133 root 1.6 if ((kqueue_fd = kqueue ()) < 0)
134     return 0;
135 root 1.1
136 root 1.2 /* Check for Mac OS X kqueue bug. */
137     ch.ident = -1;
138     ch.filter = EVFILT_READ;
139     ch.flags = EV_ADD;
140 root 1.1
141     /*
142     * If kqueue works, then kevent will succeed, and it will
143 root 1.4 * stick an error in ev. If kqueue is broken, then
144 root 1.1 * kevent will fail.
145     */
146 root 1.6 if (kevent (kqueue_fd, &ch, 1, &ev, 1, 0) != 1
147 root 1.2 || ev.ident != -1
148     || ev.flags != EV_ERROR)
149 root 1.1 {
150     /* detected broken kqueue */
151 root 1.6 close (kqueue_fd);
152     return 0;
153 root 1.1 }
154    
155     method_fudge = 1e-3; /* needed to compensate for kevent returning early */
156 root 1.5 method_modify = kqueue_modify;
157     method_poll = kqueue_poll;
158 root 1.1
159 root 1.6 kqueue_eventmax = 64; /* intiial number of events receivable per poll */
160     kqueue_events = malloc (sizeof (struct kevent) * kqueue_eventmax);
161    
162     return EVMETHOD_KQUEUE;
163 root 1.1 }
164