epoll.c revision 1.1.1.3 1 1.1 christos /*
2 1.1 christos * Copyright 2000-2007 Niels Provos <provos (at) citi.umich.edu>
3 1.1 christos * Copyright 2007-2012 Niels Provos, Nick Mathewson
4 1.1 christos *
5 1.1 christos * Redistribution and use in source and binary forms, with or without
6 1.1 christos * modification, are permitted provided that the following conditions
7 1.1 christos * are met:
8 1.1 christos * 1. Redistributions of source code must retain the above copyright
9 1.1 christos * notice, this list of conditions and the following disclaimer.
10 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright
11 1.1 christos * notice, this list of conditions and the following disclaimer in the
12 1.1 christos * documentation and/or other materials provided with the distribution.
13 1.1 christos * 3. The name of the author may not be used to endorse or promote products
14 1.1 christos * derived from this software without specific prior written permission.
15 1.1 christos *
16 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 1.1 christos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 1.1 christos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 1.1 christos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 1.1 christos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 1.1 christos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 1.1 christos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 1.1 christos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 1.1 christos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 1.1 christos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 1.1 christos */
27 1.1 christos #include "event2/event-config.h"
28 1.1 christos #include "evconfig-private.h"
29 1.1 christos
30 1.1 christos #ifdef EVENT__HAVE_EPOLL
31 1.1 christos
32 1.1 christos #include <stdint.h>
33 1.1 christos #include <sys/types.h>
34 1.1 christos #include <sys/resource.h>
35 1.1 christos #ifdef EVENT__HAVE_SYS_TIME_H
36 1.1 christos #include <sys/time.h>
37 1.1 christos #endif
38 1.1 christos #include <sys/queue.h>
39 1.1 christos #include <sys/epoll.h>
40 1.1 christos #include <signal.h>
41 1.1 christos #include <limits.h>
42 1.1 christos #include <stdio.h>
43 1.1 christos #include <stdlib.h>
44 1.1 christos #include <string.h>
45 1.1 christos #include <unistd.h>
46 1.1 christos #include <errno.h>
47 1.1 christos #ifdef EVENT__HAVE_FCNTL_H
48 1.1 christos #include <fcntl.h>
49 1.1 christos #endif
50 1.1 christos #ifdef EVENT__HAVE_SYS_TIMERFD_H
51 1.1 christos #include <sys/timerfd.h>
52 1.1 christos #endif
53 1.1 christos
54 1.1 christos #include "event-internal.h"
55 1.1 christos #include "evsignal-internal.h"
56 1.1 christos #include "event2/thread.h"
57 1.1 christos #include "evthread-internal.h"
58 1.1 christos #include "log-internal.h"
59 1.1 christos #include "evmap-internal.h"
60 1.1 christos #include "changelist-internal.h"
61 1.1 christos #include "time-internal.h"
62 1.1 christos
63 1.1.1.2 christos /* Since Linux 2.6.17, epoll is able to report about peer half-closed connection
64 1.1.1.2 christos using special EPOLLRDHUP flag on a read event.
65 1.1.1.2 christos */
66 1.1.1.2 christos #if !defined(EPOLLRDHUP)
67 1.1.1.2 christos #define EPOLLRDHUP 0
68 1.1.1.2 christos #define EARLY_CLOSE_IF_HAVE_RDHUP 0
69 1.1.1.2 christos #else
70 1.1.1.2 christos #define EARLY_CLOSE_IF_HAVE_RDHUP EV_FEATURE_EARLY_CLOSE
71 1.1.1.2 christos #endif
72 1.1.1.2 christos
73 1.1.1.2 christos #include "epolltable-internal.h"
74 1.1.1.2 christos
75 1.1 christos #if defined(EVENT__HAVE_SYS_TIMERFD_H) && \
76 1.1 christos defined(EVENT__HAVE_TIMERFD_CREATE) && \
77 1.1 christos defined(HAVE_POSIX_MONOTONIC) && defined(TFD_NONBLOCK) && \
78 1.1 christos defined(TFD_CLOEXEC)
79 1.1 christos /* Note that we only use timerfd if TFD_NONBLOCK and TFD_CLOEXEC are available
80 1.1 christos and working. This means that we can't support it on 2.6.25 (where timerfd
81 1.1 christos was introduced) or 2.6.26, since 2.6.27 introduced those flags.
82 1.1 christos */
83 1.1 christos #define USING_TIMERFD
84 1.1 christos #endif
85 1.1 christos
86 1.1 christos struct epollop {
87 1.1 christos struct epoll_event *events;
88 1.1 christos int nevents;
89 1.1 christos int epfd;
90 1.1 christos #ifdef USING_TIMERFD
91 1.1 christos int timerfd;
92 1.1 christos #endif
93 1.1 christos };
94 1.1 christos
95 1.1 christos static void *epoll_init(struct event_base *);
96 1.1 christos static int epoll_dispatch(struct event_base *, struct timeval *);
97 1.1 christos static void epoll_dealloc(struct event_base *);
98 1.1 christos
99 1.1 christos static const struct eventop epollops_changelist = {
100 1.1 christos "epoll (with changelist)",
101 1.1 christos epoll_init,
102 1.1 christos event_changelist_add_,
103 1.1 christos event_changelist_del_,
104 1.1 christos epoll_dispatch,
105 1.1 christos epoll_dealloc,
106 1.1 christos 1, /* need reinit */
107 1.1.1.2 christos EV_FEATURE_ET|EV_FEATURE_O1| EARLY_CLOSE_IF_HAVE_RDHUP,
108 1.1 christos EVENT_CHANGELIST_FDINFO_SIZE
109 1.1 christos };
110 1.1 christos
111 1.1 christos
112 1.1 christos static int epoll_nochangelist_add(struct event_base *base, evutil_socket_t fd,
113 1.1 christos short old, short events, void *p);
114 1.1 christos static int epoll_nochangelist_del(struct event_base *base, evutil_socket_t fd,
115 1.1 christos short old, short events, void *p);
116 1.1 christos
117 1.1 christos const struct eventop epollops = {
118 1.1 christos "epoll",
119 1.1 christos epoll_init,
120 1.1 christos epoll_nochangelist_add,
121 1.1 christos epoll_nochangelist_del,
122 1.1 christos epoll_dispatch,
123 1.1 christos epoll_dealloc,
124 1.1 christos 1, /* need reinit */
125 1.1.1.2 christos EV_FEATURE_ET|EV_FEATURE_O1|EV_FEATURE_EARLY_CLOSE,
126 1.1 christos 0
127 1.1 christos };
128 1.1 christos
129 1.1 christos #define INITIAL_NEVENT 32
130 1.1 christos #define MAX_NEVENT 4096
131 1.1 christos
132 1.1 christos /* On Linux kernels at least up to 2.6.24.4, epoll can't handle timeout
133 1.1 christos * values bigger than (LONG_MAX - 999ULL)/HZ. HZ in the wild can be
134 1.1 christos * as big as 1000, and LONG_MAX can be as small as (1<<31)-1, so the
135 1.1 christos * largest number of msec we can support here is 2147482. Let's
136 1.1 christos * round that down by 47 seconds.
137 1.1 christos */
138 1.1 christos #define MAX_EPOLL_TIMEOUT_MSEC (35*60*1000)
139 1.1 christos
140 1.1 christos static void *
141 1.1 christos epoll_init(struct event_base *base)
142 1.1 christos {
143 1.1 christos int epfd = -1;
144 1.1 christos struct epollop *epollop;
145 1.1 christos
146 1.1 christos #ifdef EVENT__HAVE_EPOLL_CREATE1
147 1.1 christos /* First, try the shiny new epoll_create1 interface, if we have it. */
148 1.1 christos epfd = epoll_create1(EPOLL_CLOEXEC);
149 1.1 christos #endif
150 1.1 christos if (epfd == -1) {
151 1.1 christos /* Initialize the kernel queue using the old interface. (The
152 1.1 christos size field is ignored since 2.6.8.) */
153 1.1 christos if ((epfd = epoll_create(32000)) == -1) {
154 1.1 christos if (errno != ENOSYS)
155 1.1 christos event_warn("epoll_create");
156 1.1 christos return (NULL);
157 1.1 christos }
158 1.1 christos evutil_make_socket_closeonexec(epfd);
159 1.1 christos }
160 1.1 christos
161 1.1 christos if (!(epollop = mm_calloc(1, sizeof(struct epollop)))) {
162 1.1 christos close(epfd);
163 1.1 christos return (NULL);
164 1.1 christos }
165 1.1 christos
166 1.1 christos epollop->epfd = epfd;
167 1.1 christos
168 1.1 christos /* Initialize fields */
169 1.1 christos epollop->events = mm_calloc(INITIAL_NEVENT, sizeof(struct epoll_event));
170 1.1 christos if (epollop->events == NULL) {
171 1.1 christos mm_free(epollop);
172 1.1 christos close(epfd);
173 1.1 christos return (NULL);
174 1.1 christos }
175 1.1 christos epollop->nevents = INITIAL_NEVENT;
176 1.1 christos
177 1.1 christos if ((base->flags & EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST) != 0 ||
178 1.1 christos ((base->flags & EVENT_BASE_FLAG_IGNORE_ENV) == 0 &&
179 1.1 christos evutil_getenv_("EVENT_EPOLL_USE_CHANGELIST") != NULL)) {
180 1.1 christos
181 1.1 christos base->evsel = &epollops_changelist;
182 1.1 christos }
183 1.1 christos
184 1.1 christos #ifdef USING_TIMERFD
185 1.1 christos /*
186 1.1 christos The epoll interface ordinarily gives us one-millisecond precision,
187 1.1 christos so on Linux it makes perfect sense to use the CLOCK_MONOTONIC_COARSE
188 1.1 christos timer. But when the user has set the new PRECISE_TIMER flag for an
189 1.1 christos event_base, we can try to use timerfd to give them finer granularity.
190 1.1 christos */
191 1.1 christos if ((base->flags & EVENT_BASE_FLAG_PRECISE_TIMER) &&
192 1.1 christos base->monotonic_timer.monotonic_clock == CLOCK_MONOTONIC) {
193 1.1 christos int fd;
194 1.1 christos fd = epollop->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC);
195 1.1 christos if (epollop->timerfd >= 0) {
196 1.1 christos struct epoll_event epev;
197 1.1 christos memset(&epev, 0, sizeof(epev));
198 1.1 christos epev.data.fd = epollop->timerfd;
199 1.1 christos epev.events = EPOLLIN;
200 1.1 christos if (epoll_ctl(epollop->epfd, EPOLL_CTL_ADD, fd, &epev) < 0) {
201 1.1 christos event_warn("epoll_ctl(timerfd)");
202 1.1 christos close(fd);
203 1.1 christos epollop->timerfd = -1;
204 1.1 christos }
205 1.1 christos } else {
206 1.1 christos if (errno != EINVAL && errno != ENOSYS) {
207 1.1 christos /* These errors probably mean that we were
208 1.1 christos * compiled with timerfd/TFD_* support, but
209 1.1 christos * we're running on a kernel that lacks those.
210 1.1 christos */
211 1.1 christos event_warn("timerfd_create");
212 1.1 christos }
213 1.1 christos epollop->timerfd = -1;
214 1.1 christos }
215 1.1 christos } else {
216 1.1 christos epollop->timerfd = -1;
217 1.1 christos }
218 1.1 christos #endif
219 1.1 christos
220 1.1 christos evsig_init_(base);
221 1.1 christos
222 1.1 christos return (epollop);
223 1.1 christos }
224 1.1 christos
225 1.1 christos static const char *
226 1.1 christos change_to_string(int change)
227 1.1 christos {
228 1.1 christos change &= (EV_CHANGE_ADD|EV_CHANGE_DEL);
229 1.1 christos if (change == EV_CHANGE_ADD) {
230 1.1 christos return "add";
231 1.1 christos } else if (change == EV_CHANGE_DEL) {
232 1.1 christos return "del";
233 1.1 christos } else if (change == 0) {
234 1.1 christos return "none";
235 1.1 christos } else {
236 1.1 christos return "???";
237 1.1 christos }
238 1.1 christos }
239 1.1 christos
240 1.1 christos static const char *
241 1.1 christos epoll_op_to_string(int op)
242 1.1 christos {
243 1.1 christos return op == EPOLL_CTL_ADD?"ADD":
244 1.1 christos op == EPOLL_CTL_DEL?"DEL":
245 1.1 christos op == EPOLL_CTL_MOD?"MOD":
246 1.1 christos "???";
247 1.1 christos }
248 1.1 christos
249 1.1 christos static int
250 1.1 christos epoll_apply_one_change(struct event_base *base,
251 1.1 christos struct epollop *epollop,
252 1.1 christos const struct event_change *ch)
253 1.1 christos {
254 1.1 christos struct epoll_event epev;
255 1.1 christos int op, events = 0;
256 1.1 christos int idx;
257 1.1 christos
258 1.1.1.2 christos idx = EPOLL_OP_TABLE_INDEX(ch);
259 1.1.1.2 christos op = epoll_op_table[idx].op;
260 1.1.1.2 christos events = epoll_op_table[idx].events;
261 1.1 christos
262 1.1 christos if (!events) {
263 1.1 christos EVUTIL_ASSERT(op == 0);
264 1.1 christos return 0;
265 1.1 christos }
266 1.1 christos
267 1.1 christos if ((ch->read_change|ch->write_change) & EV_CHANGE_ET)
268 1.1 christos events |= EPOLLET;
269 1.1 christos
270 1.1 christos memset(&epev, 0, sizeof(epev));
271 1.1 christos epev.data.fd = ch->fd;
272 1.1 christos epev.events = events;
273 1.1 christos if (epoll_ctl(epollop->epfd, op, ch->fd, &epev) == 0) {
274 1.1.1.2 christos event_debug(("Epoll %s(%d) on fd %d okay. [old events were %d; read change was %d; write change was %d; close change was %d]",
275 1.1 christos epoll_op_to_string(op),
276 1.1 christos (int)epev.events,
277 1.1 christos (int)ch->fd,
278 1.1 christos ch->old_events,
279 1.1 christos ch->read_change,
280 1.1.1.2 christos ch->write_change,
281 1.1.1.2 christos ch->close_change));
282 1.1 christos return 0;
283 1.1 christos }
284 1.1 christos
285 1.1 christos switch (op) {
286 1.1 christos case EPOLL_CTL_MOD:
287 1.1 christos if (errno == ENOENT) {
288 1.1 christos /* If a MOD operation fails with ENOENT, the
289 1.1 christos * fd was probably closed and re-opened. We
290 1.1 christos * should retry the operation as an ADD.
291 1.1 christos */
292 1.1 christos if (epoll_ctl(epollop->epfd, EPOLL_CTL_ADD, ch->fd, &epev) == -1) {
293 1.1 christos event_warn("Epoll MOD(%d) on %d retried as ADD; that failed too",
294 1.1 christos (int)epev.events, ch->fd);
295 1.1 christos return -1;
296 1.1 christos } else {
297 1.1 christos event_debug(("Epoll MOD(%d) on %d retried as ADD; succeeded.",
298 1.1 christos (int)epev.events,
299 1.1 christos ch->fd));
300 1.1 christos return 0;
301 1.1 christos }
302 1.1 christos }
303 1.1 christos break;
304 1.1 christos case EPOLL_CTL_ADD:
305 1.1 christos if (errno == EEXIST) {
306 1.1 christos /* If an ADD operation fails with EEXIST,
307 1.1 christos * either the operation was redundant (as with a
308 1.1 christos * precautionary add), or we ran into a fun
309 1.1 christos * kernel bug where using dup*() to duplicate the
310 1.1 christos * same file into the same fd gives you the same epitem
311 1.1 christos * rather than a fresh one. For the second case,
312 1.1 christos * we must retry with MOD. */
313 1.1 christos if (epoll_ctl(epollop->epfd, EPOLL_CTL_MOD, ch->fd, &epev) == -1) {
314 1.1 christos event_warn("Epoll ADD(%d) on %d retried as MOD; that failed too",
315 1.1 christos (int)epev.events, ch->fd);
316 1.1 christos return -1;
317 1.1 christos } else {
318 1.1 christos event_debug(("Epoll ADD(%d) on %d retried as MOD; succeeded.",
319 1.1 christos (int)epev.events,
320 1.1 christos ch->fd));
321 1.1 christos return 0;
322 1.1 christos }
323 1.1 christos }
324 1.1 christos break;
325 1.1 christos case EPOLL_CTL_DEL:
326 1.1 christos if (errno == ENOENT || errno == EBADF || errno == EPERM) {
327 1.1 christos /* If a delete fails with one of these errors,
328 1.1 christos * that's fine too: we closed the fd before we
329 1.1 christos * got around to calling epoll_dispatch. */
330 1.1 christos event_debug(("Epoll DEL(%d) on fd %d gave %s: DEL was unnecessary.",
331 1.1 christos (int)epev.events,
332 1.1 christos ch->fd,
333 1.1 christos strerror(errno)));
334 1.1 christos return 0;
335 1.1 christos }
336 1.1 christos break;
337 1.1 christos default:
338 1.1 christos break;
339 1.1 christos }
340 1.1 christos
341 1.1.1.2 christos event_warn("Epoll %s(%d) on fd %d failed. Old events were %d; read change was %d (%s); write change was %d (%s); close change was %d (%s)",
342 1.1 christos epoll_op_to_string(op),
343 1.1 christos (int)epev.events,
344 1.1 christos ch->fd,
345 1.1 christos ch->old_events,
346 1.1 christos ch->read_change,
347 1.1 christos change_to_string(ch->read_change),
348 1.1 christos ch->write_change,
349 1.1.1.2 christos change_to_string(ch->write_change),
350 1.1.1.2 christos ch->close_change,
351 1.1.1.2 christos change_to_string(ch->close_change));
352 1.1 christos
353 1.1 christos return -1;
354 1.1 christos }
355 1.1 christos
356 1.1 christos static int
357 1.1 christos epoll_apply_changes(struct event_base *base)
358 1.1 christos {
359 1.1 christos struct event_changelist *changelist = &base->changelist;
360 1.1 christos struct epollop *epollop = base->evbase;
361 1.1 christos struct event_change *ch;
362 1.1 christos
363 1.1 christos int r = 0;
364 1.1 christos int i;
365 1.1 christos
366 1.1 christos for (i = 0; i < changelist->n_changes; ++i) {
367 1.1 christos ch = &changelist->changes[i];
368 1.1 christos if (epoll_apply_one_change(base, epollop, ch) < 0)
369 1.1 christos r = -1;
370 1.1 christos }
371 1.1 christos
372 1.1 christos return (r);
373 1.1 christos }
374 1.1 christos
375 1.1 christos static int
376 1.1 christos epoll_nochangelist_add(struct event_base *base, evutil_socket_t fd,
377 1.1 christos short old, short events, void *p)
378 1.1 christos {
379 1.1 christos struct event_change ch;
380 1.1 christos ch.fd = fd;
381 1.1 christos ch.old_events = old;
382 1.1.1.2 christos ch.read_change = ch.write_change = ch.close_change = 0;
383 1.1 christos if (events & EV_WRITE)
384 1.1 christos ch.write_change = EV_CHANGE_ADD |
385 1.1 christos (events & EV_ET);
386 1.1 christos if (events & EV_READ)
387 1.1 christos ch.read_change = EV_CHANGE_ADD |
388 1.1 christos (events & EV_ET);
389 1.1.1.2 christos if (events & EV_CLOSED)
390 1.1.1.2 christos ch.close_change = EV_CHANGE_ADD |
391 1.1.1.2 christos (events & EV_ET);
392 1.1 christos
393 1.1 christos return epoll_apply_one_change(base, base->evbase, &ch);
394 1.1 christos }
395 1.1 christos
396 1.1 christos static int
397 1.1 christos epoll_nochangelist_del(struct event_base *base, evutil_socket_t fd,
398 1.1 christos short old, short events, void *p)
399 1.1 christos {
400 1.1 christos struct event_change ch;
401 1.1 christos ch.fd = fd;
402 1.1 christos ch.old_events = old;
403 1.1.1.2 christos ch.read_change = ch.write_change = ch.close_change = 0;
404 1.1 christos if (events & EV_WRITE)
405 1.1 christos ch.write_change = EV_CHANGE_DEL;
406 1.1 christos if (events & EV_READ)
407 1.1 christos ch.read_change = EV_CHANGE_DEL;
408 1.1.1.2 christos if (events & EV_CLOSED)
409 1.1.1.2 christos ch.close_change = EV_CHANGE_DEL;
410 1.1 christos
411 1.1 christos return epoll_apply_one_change(base, base->evbase, &ch);
412 1.1 christos }
413 1.1 christos
414 1.1 christos static int
415 1.1 christos epoll_dispatch(struct event_base *base, struct timeval *tv)
416 1.1 christos {
417 1.1 christos struct epollop *epollop = base->evbase;
418 1.1 christos struct epoll_event *events = epollop->events;
419 1.1 christos int i, res;
420 1.1 christos long timeout = -1;
421 1.1 christos
422 1.1 christos #ifdef USING_TIMERFD
423 1.1 christos if (epollop->timerfd >= 0) {
424 1.1 christos struct itimerspec is;
425 1.1 christos is.it_interval.tv_sec = 0;
426 1.1 christos is.it_interval.tv_nsec = 0;
427 1.1 christos if (tv == NULL) {
428 1.1 christos /* No timeout; disarm the timer. */
429 1.1 christos is.it_value.tv_sec = 0;
430 1.1 christos is.it_value.tv_nsec = 0;
431 1.1 christos } else {
432 1.1 christos if (tv->tv_sec == 0 && tv->tv_usec == 0) {
433 1.1 christos /* we need to exit immediately; timerfd can't
434 1.1 christos * do that. */
435 1.1 christos timeout = 0;
436 1.1 christos }
437 1.1 christos is.it_value.tv_sec = tv->tv_sec;
438 1.1 christos is.it_value.tv_nsec = tv->tv_usec * 1000;
439 1.1 christos }
440 1.1 christos /* TODO: we could avoid unnecessary syscalls here by only
441 1.1 christos calling timerfd_settime when the top timeout changes, or
442 1.1 christos when we're called with a different timeval.
443 1.1 christos */
444 1.1 christos if (timerfd_settime(epollop->timerfd, 0, &is, NULL) < 0) {
445 1.1 christos event_warn("timerfd_settime");
446 1.1 christos }
447 1.1 christos } else
448 1.1 christos #endif
449 1.1 christos if (tv != NULL) {
450 1.1 christos timeout = evutil_tv_to_msec_(tv);
451 1.1 christos if (timeout < 0 || timeout > MAX_EPOLL_TIMEOUT_MSEC) {
452 1.1 christos /* Linux kernels can wait forever if the timeout is
453 1.1 christos * too big; see comment on MAX_EPOLL_TIMEOUT_MSEC. */
454 1.1 christos timeout = MAX_EPOLL_TIMEOUT_MSEC;
455 1.1 christos }
456 1.1 christos }
457 1.1 christos
458 1.1 christos epoll_apply_changes(base);
459 1.1 christos event_changelist_remove_all_(&base->changelist, base);
460 1.1 christos
461 1.1 christos EVBASE_RELEASE_LOCK(base, th_base_lock);
462 1.1 christos
463 1.1 christos res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);
464 1.1 christos
465 1.1 christos EVBASE_ACQUIRE_LOCK(base, th_base_lock);
466 1.1 christos
467 1.1 christos if (res == -1) {
468 1.1 christos if (errno != EINTR) {
469 1.1 christos event_warn("epoll_wait");
470 1.1 christos return (-1);
471 1.1 christos }
472 1.1 christos
473 1.1 christos return (0);
474 1.1 christos }
475 1.1 christos
476 1.1 christos event_debug(("%s: epoll_wait reports %d", __func__, res));
477 1.1 christos EVUTIL_ASSERT(res <= epollop->nevents);
478 1.1 christos
479 1.1 christos for (i = 0; i < res; i++) {
480 1.1 christos int what = events[i].events;
481 1.1 christos short ev = 0;
482 1.1 christos #ifdef USING_TIMERFD
483 1.1 christos if (events[i].data.fd == epollop->timerfd)
484 1.1 christos continue;
485 1.1 christos #endif
486 1.1 christos
487 1.1 christos if (what & (EPOLLHUP|EPOLLERR)) {
488 1.1 christos ev = EV_READ | EV_WRITE;
489 1.1 christos } else {
490 1.1 christos if (what & EPOLLIN)
491 1.1 christos ev |= EV_READ;
492 1.1 christos if (what & EPOLLOUT)
493 1.1 christos ev |= EV_WRITE;
494 1.1.1.2 christos if (what & EPOLLRDHUP)
495 1.1.1.2 christos ev |= EV_CLOSED;
496 1.1 christos }
497 1.1 christos
498 1.1 christos if (!ev)
499 1.1 christos continue;
500 1.1 christos
501 1.1 christos evmap_io_active_(base, events[i].data.fd, ev | EV_ET);
502 1.1 christos }
503 1.1 christos
504 1.1 christos if (res == epollop->nevents && epollop->nevents < MAX_NEVENT) {
505 1.1 christos /* We used all of the event space this time. We should
506 1.1 christos be ready for more events next time. */
507 1.1 christos int new_nevents = epollop->nevents * 2;
508 1.1 christos struct epoll_event *new_events;
509 1.1 christos
510 1.1 christos new_events = mm_realloc(epollop->events,
511 1.1 christos new_nevents * sizeof(struct epoll_event));
512 1.1 christos if (new_events) {
513 1.1 christos epollop->events = new_events;
514 1.1 christos epollop->nevents = new_nevents;
515 1.1 christos }
516 1.1 christos }
517 1.1 christos
518 1.1 christos return (0);
519 1.1 christos }
520 1.1 christos
521 1.1 christos
522 1.1 christos static void
523 1.1 christos epoll_dealloc(struct event_base *base)
524 1.1 christos {
525 1.1 christos struct epollop *epollop = base->evbase;
526 1.1 christos
527 1.1 christos evsig_dealloc_(base);
528 1.1 christos if (epollop->events)
529 1.1 christos mm_free(epollop->events);
530 1.1 christos if (epollop->epfd >= 0)
531 1.1 christos close(epollop->epfd);
532 1.1 christos #ifdef USING_TIMERFD
533 1.1 christos if (epollop->timerfd >= 0)
534 1.1 christos close(epollop->timerfd);
535 1.1 christos #endif
536 1.1 christos
537 1.1 christos memset(epollop, 0, sizeof(struct epollop));
538 1.1 christos mm_free(epollop);
539 1.1 christos }
540 1.1 christos
541 1.1 christos #endif /* EVENT__HAVE_EPOLL */
542