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