Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1261)

Side by Side Diff: third_party/libevent/kqueue.c

Issue 1531573008: move libevent into base (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix shim path Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/libevent/http-internal.h ('k') | third_party/libevent/libevent.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 #define _GNU_SOURCE 1
34
35 #include <sys/types.h>
36 #ifdef HAVE_SYS_TIME_H
37 #include <sys/time.h>
38 #else
39 #include <sys/_libevent_time.h>
40 #endif
41 #include <sys/queue.h>
42 #include <sys/event.h>
43 #include <signal.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <errno.h>
49 #include <assert.h>
50 #ifdef HAVE_INTTYPES_H
51 #include <inttypes.h>
52 #endif
53
54 /* Some platforms apparently define the udata field of struct kevent as
55 * intptr_t, whereas others define it as void*. There doesn't seem to be an
56 * easy way to tell them apart via autoconf, so we need to use OS macros. */
57 #if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) & & !defined(__darwin__) && !defined(__APPLE__)
58 #define PTR_TO_UDATA(x) ((intptr_t)(x))
59 #else
60 #define PTR_TO_UDATA(x) (x)
61 #endif
62
63 #include "event.h"
64 #include "event-internal.h"
65 #include "log.h"
66 #include "evsignal.h"
67
68 #define EVLIST_X_KQINKERNEL 0x1000
69
70 #define NEVENT 64
71
72 struct kqop {
73 struct kevent *changes;
74 int nchanges;
75 struct kevent *events;
76 struct event_list evsigevents[NSIG];
77 int nevents;
78 int kq;
79 pid_t pid;
80 };
81
82 static void *kq_init (struct event_base *);
83 static int kq_add (void *, struct event *);
84 static int kq_del (void *, struct event *);
85 static int kq_dispatch (struct event_base *, void *, struct timeval *);
86 static int kq_insert (struct kqop *, struct kevent *);
87 static void kq_dealloc (struct event_base *, void *);
88
89 const struct eventop kqops = {
90 "kqueue",
91 kq_init,
92 kq_add,
93 kq_del,
94 kq_dispatch,
95 kq_dealloc,
96 1 /* need reinit */
97 };
98
99 static void *
100 kq_init(struct event_base *base)
101 {
102 int i, kq;
103 struct kqop *kqueueop;
104
105 /* Disable kqueue when this environment variable is set */
106 if (evutil_getenv("EVENT_NOKQUEUE"))
107 return (NULL);
108
109 if (!(kqueueop = calloc(1, sizeof(struct kqop))))
110 return (NULL);
111
112 /* Initalize the kernel queue */
113
114 if ((kq = kqueue()) == -1) {
115 event_warn("kqueue");
116 free (kqueueop);
117 return (NULL);
118 }
119
120 kqueueop->kq = kq;
121
122 kqueueop->pid = getpid();
123
124 /* Initalize fields */
125 kqueueop->changes = malloc(NEVENT * sizeof(struct kevent));
126 if (kqueueop->changes == NULL) {
127 free (kqueueop);
128 return (NULL);
129 }
130 kqueueop->events = malloc(NEVENT * sizeof(struct kevent));
131 if (kqueueop->events == NULL) {
132 free (kqueueop->changes);
133 free (kqueueop);
134 return (NULL);
135 }
136 kqueueop->nevents = NEVENT;
137
138 /* we need to keep track of multiple events per signal */
139 for (i = 0; i < NSIG; ++i) {
140 TAILQ_INIT(&kqueueop->evsigevents[i]);
141 }
142
143 /* Check for Mac OS X kqueue bug. */
144 memset(&kqueueop->changes[0], 0, sizeof kqueueop->changes[0]);
145 kqueueop->changes[0].ident = -1;
146 kqueueop->changes[0].filter = EVFILT_READ;
147 kqueueop->changes[0].flags = EV_ADD;
148 /*
149 * If kqueue works, then kevent will succeed, and it will
150 * stick an error in events[0]. If kqueue is broken, then
151 * kevent will fail.
152 */
153 if (kevent(kq,
154 kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 ||
155 kqueueop->events[0].ident != -1 ||
156 kqueueop->events[0].flags != EV_ERROR) {
157 event_warn("%s: detected broken kqueue; not using.", __func__);
158 free(kqueueop->changes);
159 free(kqueueop->events);
160 free(kqueueop);
161 close(kq);
162 return (NULL);
163 }
164
165 return (kqueueop);
166 }
167
168 static int
169 kq_insert(struct kqop *kqop, struct kevent *kev)
170 {
171 int nevents = kqop->nevents;
172
173 if (kqop->nchanges == nevents) {
174 struct kevent *newchange;
175 struct kevent *newresult;
176
177 nevents *= 2;
178
179 newchange = realloc(kqop->changes,
180 nevents * sizeof(struct kevent));
181 if (newchange == NULL) {
182 event_warn("%s: malloc", __func__);
183 return (-1);
184 }
185 kqop->changes = newchange;
186
187 newresult = realloc(kqop->events,
188 nevents * sizeof(struct kevent));
189
190 /*
191 * If we fail, we don't have to worry about freeing,
192 * the next realloc will pick it up.
193 */
194 if (newresult == NULL) {
195 event_warn("%s: malloc", __func__);
196 return (-1);
197 }
198 kqop->events = newresult;
199
200 kqop->nevents = nevents;
201 }
202
203 memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
204
205 event_debug(("%s: fd %d %s%s",
206 __func__, (int)kev->ident,
207 kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
208 kev->flags == EV_DELETE ? " (del)" : ""));
209
210 return (0);
211 }
212
213 static void
214 kq_sighandler(int sig)
215 {
216 /* Do nothing here */
217 }
218
219 static int
220 kq_dispatch(struct event_base *base, void *arg, struct timeval *tv)
221 {
222 struct kqop *kqop = arg;
223 struct kevent *changes = kqop->changes;
224 struct kevent *events = kqop->events;
225 struct event *ev;
226 struct timespec ts, *ts_p = NULL;
227 int i, res;
228
229 if (tv != NULL) {
230 TIMEVAL_TO_TIMESPEC(tv, &ts);
231 ts_p = &ts;
232 }
233
234 res = kevent(kqop->kq, changes, kqop->nchanges,
235 events, kqop->nevents, ts_p);
236 kqop->nchanges = 0;
237 if (res == -1) {
238 if (errno != EINTR) {
239 event_warn("kevent");
240 return (-1);
241 }
242
243 return (0);
244 }
245
246 event_debug(("%s: kevent reports %d", __func__, res));
247
248 for (i = 0; i < res; i++) {
249 int which = 0;
250
251 if (events[i].flags & EV_ERROR) {
252 /*
253 * Error messages that can happen, when a delete fails.
254 * EBADF happens when the file discriptor has been
255 * closed,
256 * ENOENT when the file discriptor was closed and
257 * then reopened.
258 * EINVAL for some reasons not understood; EINVAL
259 * should not be returned ever; but FreeBSD does :-\
260 * An error is also indicated when a callback deletes
261 * an event we are still processing. In that case
262 * the data field is set to ENOENT.
263 */
264 if (events[i].data == EBADF ||
265 events[i].data == EINVAL ||
266 events[i].data == ENOENT)
267 continue;
268 errno = events[i].data;
269 return (-1);
270 }
271
272 if (events[i].filter == EVFILT_READ) {
273 which |= EV_READ;
274 } else if (events[i].filter == EVFILT_WRITE) {
275 which |= EV_WRITE;
276 } else if (events[i].filter == EVFILT_SIGNAL) {
277 which |= EV_SIGNAL;
278 }
279
280 if (!which)
281 continue;
282
283 if (events[i].filter == EVFILT_SIGNAL) {
284 struct event_list *head =
285 (struct event_list *)events[i].udata;
286 TAILQ_FOREACH(ev, head, ev_signal_next) {
287 event_active(ev, which, events[i].data);
288 }
289 } else {
290 ev = (struct event *)events[i].udata;
291
292 if (!(ev->ev_events & EV_PERSIST))
293 ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
294
295 event_active(ev, which, 1);
296 }
297 }
298
299 return (0);
300 }
301
302
303 static int
304 kq_add(void *arg, struct event *ev)
305 {
306 struct kqop *kqop = arg;
307 struct kevent kev;
308
309 if (ev->ev_events & EV_SIGNAL) {
310 int nsignal = EVENT_SIGNAL(ev);
311
312 assert(nsignal >= 0 && nsignal < NSIG);
313 if (TAILQ_EMPTY(&kqop->evsigevents[nsignal])) {
314 struct timespec timeout = { 0, 0 };
315
316 memset(&kev, 0, sizeof(kev));
317 kev.ident = nsignal;
318 kev.filter = EVFILT_SIGNAL;
319 kev.flags = EV_ADD;
320 kev.udata = PTR_TO_UDATA(&kqop->evsigevents[nsignal]);
321
322 /* Be ready for the signal if it is sent any
323 * time between now and the next call to
324 * kq_dispatch. */
325 if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
326 return (-1);
327
328 if (_evsignal_set_handler(ev->ev_base, nsignal,
329 kq_sighandler) == -1)
330 return (-1);
331 }
332
333 TAILQ_INSERT_TAIL(&kqop->evsigevents[nsignal], ev,
334 ev_signal_next);
335 ev->ev_flags |= EVLIST_X_KQINKERNEL;
336 return (0);
337 }
338
339 if (ev->ev_events & EV_READ) {
340 memset(&kev, 0, sizeof(kev));
341 kev.ident = ev->ev_fd;
342 kev.filter = EVFILT_READ;
343 #ifdef NOTE_EOF
344 /* Make it behave like select() and poll() */
345 kev.fflags = NOTE_EOF;
346 #endif
347 kev.flags = EV_ADD;
348 if (!(ev->ev_events & EV_PERSIST))
349 kev.flags |= EV_ONESHOT;
350 kev.udata = PTR_TO_UDATA(ev);
351
352 if (kq_insert(kqop, &kev) == -1)
353 return (-1);
354
355 ev->ev_flags |= EVLIST_X_KQINKERNEL;
356 }
357
358 if (ev->ev_events & EV_WRITE) {
359 memset(&kev, 0, sizeof(kev));
360 kev.ident = ev->ev_fd;
361 kev.filter = EVFILT_WRITE;
362 kev.flags = EV_ADD;
363 if (!(ev->ev_events & EV_PERSIST))
364 kev.flags |= EV_ONESHOT;
365 kev.udata = PTR_TO_UDATA(ev);
366
367 if (kq_insert(kqop, &kev) == -1)
368 return (-1);
369
370 ev->ev_flags |= EVLIST_X_KQINKERNEL;
371 }
372
373 return (0);
374 }
375
376 static int
377 kq_del(void *arg, struct event *ev)
378 {
379 struct kqop *kqop = arg;
380 struct kevent kev;
381
382 if (!(ev->ev_flags & EVLIST_X_KQINKERNEL))
383 return (0);
384
385 if (ev->ev_events & EV_SIGNAL) {
386 int nsignal = EVENT_SIGNAL(ev);
387 struct timespec timeout = { 0, 0 };
388
389 assert(nsignal >= 0 && nsignal < NSIG);
390 TAILQ_REMOVE(&kqop->evsigevents[nsignal], ev, ev_signal_next);
391 if (TAILQ_EMPTY(&kqop->evsigevents[nsignal])) {
392 memset(&kev, 0, sizeof(kev));
393 kev.ident = nsignal;
394 kev.filter = EVFILT_SIGNAL;
395 kev.flags = EV_DELETE;
396
397 /* Because we insert signal events
398 * immediately, we need to delete them
399 * immediately, too */
400 if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
401 return (-1);
402
403 if (_evsignal_restore_handler(ev->ev_base,
404 nsignal) == -1)
405 return (-1);
406 }
407
408 ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
409 return (0);
410 }
411
412 if (ev->ev_events & EV_READ) {
413 memset(&kev, 0, sizeof(kev));
414 kev.ident = ev->ev_fd;
415 kev.filter = EVFILT_READ;
416 kev.flags = EV_DELETE;
417
418 if (kq_insert(kqop, &kev) == -1)
419 return (-1);
420
421 ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
422 }
423
424 if (ev->ev_events & EV_WRITE) {
425 memset(&kev, 0, sizeof(kev));
426 kev.ident = ev->ev_fd;
427 kev.filter = EVFILT_WRITE;
428 kev.flags = EV_DELETE;
429
430 if (kq_insert(kqop, &kev) == -1)
431 return (-1);
432
433 ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
434 }
435
436 return (0);
437 }
438
439 static void
440 kq_dealloc(struct event_base *base, void *arg)
441 {
442 struct kqop *kqop = arg;
443
444 evsignal_dealloc(base);
445
446 if (kqop->changes)
447 free(kqop->changes);
448 if (kqop->events)
449 free(kqop->events);
450 if (kqop->kq >= 0 && kqop->pid == getpid())
451 close(kqop->kq);
452
453 memset(kqop, 0, sizeof(struct kqop));
454 free(kqop);
455 }
OLDNEW
« no previous file with comments | « third_party/libevent/http-internal.h ('k') | third_party/libevent/libevent.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698