epoll.c revision 1.6 1 1.5 christos /* $NetBSD: epoll.c,v 1.6 2024/08/18 20:47:21 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.6 christos #define PRINT_CHANGES(op, events, ch, status) \
252 1.6 christos "Epoll %s(%d) on fd %d " status ". " \
253 1.6 christos "Old events were %d; " \
254 1.6 christos "read change was %d (%s); " \
255 1.6 christos "write change was %d (%s); " \
256 1.6 christos "close change was %d (%s)", \
257 1.6 christos epoll_op_to_string(op), \
258 1.6 christos events, \
259 1.6 christos ch->fd, \
260 1.6 christos ch->old_events, \
261 1.6 christos ch->read_change, \
262 1.6 christos change_to_string(ch->read_change), \
263 1.6 christos ch->write_change, \
264 1.6 christos change_to_string(ch->write_change), \
265 1.6 christos ch->close_change, \
266 1.6 christos change_to_string(ch->close_change)
267 1.6 christos
268 1.1 christos static int
269 1.1 christos epoll_apply_one_change(struct event_base *base,
270 1.1 christos struct epollop *epollop,
271 1.1 christos const struct event_change *ch)
272 1.1 christos {
273 1.1 christos struct epoll_event epev;
274 1.1 christos int op, events = 0;
275 1.1 christos int idx;
276 1.1 christos
277 1.2 christos idx = EPOLL_OP_TABLE_INDEX(ch);
278 1.2 christos op = epoll_op_table[idx].op;
279 1.2 christos events = epoll_op_table[idx].events;
280 1.1 christos
281 1.1 christos if (!events) {
282 1.1 christos EVUTIL_ASSERT(op == 0);
283 1.1 christos return 0;
284 1.1 christos }
285 1.1 christos
286 1.6 christos if ((ch->read_change|ch->write_change|ch->close_change) & EV_CHANGE_ET)
287 1.1 christos events |= EPOLLET;
288 1.1 christos
289 1.1 christos memset(&epev, 0, sizeof(epev));
290 1.1 christos epev.data.fd = ch->fd;
291 1.1 christos epev.events = events;
292 1.1 christos if (epoll_ctl(epollop->epfd, op, ch->fd, &epev) == 0) {
293 1.6 christos event_debug((PRINT_CHANGES(op, epev.events, ch, "okay")));
294 1.1 christos return 0;
295 1.1 christos }
296 1.1 christos
297 1.1 christos switch (op) {
298 1.1 christos case EPOLL_CTL_MOD:
299 1.1 christos if (errno == ENOENT) {
300 1.1 christos /* If a MOD operation fails with ENOENT, the
301 1.1 christos * fd was probably closed and re-opened. We
302 1.1 christos * should retry the operation as an ADD.
303 1.1 christos */
304 1.1 christos if (epoll_ctl(epollop->epfd, EPOLL_CTL_ADD, ch->fd, &epev) == -1) {
305 1.1 christos event_warn("Epoll MOD(%d) on %d retried as ADD; that failed too",
306 1.1 christos (int)epev.events, ch->fd);
307 1.1 christos return -1;
308 1.1 christos } else {
309 1.1 christos event_debug(("Epoll MOD(%d) on %d retried as ADD; succeeded.",
310 1.1 christos (int)epev.events,
311 1.1 christos ch->fd));
312 1.1 christos return 0;
313 1.1 christos }
314 1.1 christos }
315 1.1 christos break;
316 1.1 christos case EPOLL_CTL_ADD:
317 1.1 christos if (errno == EEXIST) {
318 1.1 christos /* If an ADD operation fails with EEXIST,
319 1.1 christos * either the operation was redundant (as with a
320 1.1 christos * precautionary add), or we ran into a fun
321 1.1 christos * kernel bug where using dup*() to duplicate the
322 1.1 christos * same file into the same fd gives you the same epitem
323 1.1 christos * rather than a fresh one. For the second case,
324 1.1 christos * we must retry with MOD. */
325 1.1 christos if (epoll_ctl(epollop->epfd, EPOLL_CTL_MOD, ch->fd, &epev) == -1) {
326 1.1 christos event_warn("Epoll ADD(%d) on %d retried as MOD; that failed too",
327 1.1 christos (int)epev.events, ch->fd);
328 1.1 christos return -1;
329 1.1 christos } else {
330 1.1 christos event_debug(("Epoll ADD(%d) on %d retried as MOD; succeeded.",
331 1.1 christos (int)epev.events,
332 1.1 christos ch->fd));
333 1.1 christos return 0;
334 1.1 christos }
335 1.1 christos }
336 1.1 christos break;
337 1.1 christos case EPOLL_CTL_DEL:
338 1.1 christos if (errno == ENOENT || errno == EBADF || errno == EPERM) {
339 1.1 christos /* If a delete fails with one of these errors,
340 1.1 christos * that's fine too: we closed the fd before we
341 1.1 christos * got around to calling epoll_dispatch. */
342 1.1 christos event_debug(("Epoll DEL(%d) on fd %d gave %s: DEL was unnecessary.",
343 1.1 christos (int)epev.events,
344 1.1 christos ch->fd,
345 1.1 christos strerror(errno)));
346 1.1 christos return 0;
347 1.1 christos }
348 1.1 christos break;
349 1.1 christos default:
350 1.1 christos break;
351 1.1 christos }
352 1.1 christos
353 1.6 christos event_warn(PRINT_CHANGES(op, epev.events, ch, "failed"));
354 1.1 christos return -1;
355 1.1 christos }
356 1.1 christos
357 1.1 christos static int
358 1.1 christos epoll_apply_changes(struct event_base *base)
359 1.1 christos {
360 1.1 christos struct event_changelist *changelist = &base->changelist;
361 1.1 christos struct epollop *epollop = base->evbase;
362 1.1 christos struct event_change *ch;
363 1.1 christos
364 1.1 christos int r = 0;
365 1.1 christos int i;
366 1.1 christos
367 1.1 christos for (i = 0; i < changelist->n_changes; ++i) {
368 1.1 christos ch = &changelist->changes[i];
369 1.1 christos if (epoll_apply_one_change(base, epollop, ch) < 0)
370 1.1 christos r = -1;
371 1.1 christos }
372 1.1 christos
373 1.1 christos return (r);
374 1.1 christos }
375 1.1 christos
376 1.1 christos static int
377 1.1 christos epoll_nochangelist_add(struct event_base *base, evutil_socket_t fd,
378 1.1 christos short old, short events, void *p)
379 1.1 christos {
380 1.1 christos struct event_change ch;
381 1.1 christos ch.fd = fd;
382 1.1 christos ch.old_events = old;
383 1.2 christos ch.read_change = ch.write_change = ch.close_change = 0;
384 1.1 christos if (events & EV_WRITE)
385 1.1 christos ch.write_change = EV_CHANGE_ADD |
386 1.1 christos (events & EV_ET);
387 1.1 christos if (events & EV_READ)
388 1.1 christos ch.read_change = EV_CHANGE_ADD |
389 1.1 christos (events & EV_ET);
390 1.2 christos if (events & EV_CLOSED)
391 1.2 christos ch.close_change = EV_CHANGE_ADD |
392 1.2 christos (events & EV_ET);
393 1.1 christos
394 1.1 christos return epoll_apply_one_change(base, base->evbase, &ch);
395 1.1 christos }
396 1.1 christos
397 1.1 christos static int
398 1.1 christos epoll_nochangelist_del(struct event_base *base, evutil_socket_t fd,
399 1.1 christos short old, short events, void *p)
400 1.1 christos {
401 1.1 christos struct event_change ch;
402 1.1 christos ch.fd = fd;
403 1.1 christos ch.old_events = old;
404 1.2 christos ch.read_change = ch.write_change = ch.close_change = 0;
405 1.1 christos if (events & EV_WRITE)
406 1.6 christos ch.write_change = EV_CHANGE_DEL |
407 1.6 christos (events & EV_ET);
408 1.1 christos if (events & EV_READ)
409 1.6 christos ch.read_change = EV_CHANGE_DEL |
410 1.6 christos (events & EV_ET);
411 1.2 christos if (events & EV_CLOSED)
412 1.6 christos ch.close_change = EV_CHANGE_DEL |
413 1.6 christos (events & EV_ET);
414 1.1 christos
415 1.1 christos return epoll_apply_one_change(base, base->evbase, &ch);
416 1.1 christos }
417 1.1 christos
418 1.1 christos static int
419 1.1 christos epoll_dispatch(struct event_base *base, struct timeval *tv)
420 1.1 christos {
421 1.1 christos struct epollop *epollop = base->evbase;
422 1.1 christos struct epoll_event *events = epollop->events;
423 1.1 christos int i, res;
424 1.1 christos long timeout = -1;
425 1.1 christos
426 1.1 christos #ifdef USING_TIMERFD
427 1.1 christos if (epollop->timerfd >= 0) {
428 1.1 christos struct itimerspec is;
429 1.1 christos is.it_interval.tv_sec = 0;
430 1.1 christos is.it_interval.tv_nsec = 0;
431 1.1 christos if (tv == NULL) {
432 1.1 christos /* No timeout; disarm the timer. */
433 1.1 christos is.it_value.tv_sec = 0;
434 1.1 christos is.it_value.tv_nsec = 0;
435 1.1 christos } else {
436 1.1 christos if (tv->tv_sec == 0 && tv->tv_usec == 0) {
437 1.1 christos /* we need to exit immediately; timerfd can't
438 1.1 christos * do that. */
439 1.1 christos timeout = 0;
440 1.1 christos }
441 1.1 christos is.it_value.tv_sec = tv->tv_sec;
442 1.1 christos is.it_value.tv_nsec = tv->tv_usec * 1000;
443 1.1 christos }
444 1.1 christos /* TODO: we could avoid unnecessary syscalls here by only
445 1.1 christos calling timerfd_settime when the top timeout changes, or
446 1.1 christos when we're called with a different timeval.
447 1.1 christos */
448 1.1 christos if (timerfd_settime(epollop->timerfd, 0, &is, NULL) < 0) {
449 1.1 christos event_warn("timerfd_settime");
450 1.1 christos }
451 1.1 christos } else
452 1.1 christos #endif
453 1.1 christos if (tv != NULL) {
454 1.1 christos timeout = evutil_tv_to_msec_(tv);
455 1.1 christos if (timeout < 0 || timeout > MAX_EPOLL_TIMEOUT_MSEC) {
456 1.1 christos /* Linux kernels can wait forever if the timeout is
457 1.1 christos * too big; see comment on MAX_EPOLL_TIMEOUT_MSEC. */
458 1.1 christos timeout = MAX_EPOLL_TIMEOUT_MSEC;
459 1.1 christos }
460 1.1 christos }
461 1.1 christos
462 1.1 christos epoll_apply_changes(base);
463 1.1 christos event_changelist_remove_all_(&base->changelist, base);
464 1.1 christos
465 1.1 christos EVBASE_RELEASE_LOCK(base, th_base_lock);
466 1.1 christos
467 1.1 christos res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);
468 1.1 christos
469 1.1 christos EVBASE_ACQUIRE_LOCK(base, th_base_lock);
470 1.1 christos
471 1.1 christos if (res == -1) {
472 1.1 christos if (errno != EINTR) {
473 1.1 christos event_warn("epoll_wait");
474 1.1 christos return (-1);
475 1.1 christos }
476 1.1 christos
477 1.1 christos return (0);
478 1.1 christos }
479 1.1 christos
480 1.1 christos event_debug(("%s: epoll_wait reports %d", __func__, res));
481 1.1 christos EVUTIL_ASSERT(res <= epollop->nevents);
482 1.1 christos
483 1.1 christos for (i = 0; i < res; i++) {
484 1.1 christos int what = events[i].events;
485 1.1 christos short ev = 0;
486 1.1 christos #ifdef USING_TIMERFD
487 1.1 christos if (events[i].data.fd == epollop->timerfd)
488 1.1 christos continue;
489 1.1 christos #endif
490 1.1 christos
491 1.6 christos if (what & EPOLLERR) {
492 1.6 christos ev = EV_READ | EV_WRITE;
493 1.6 christos } else if ((what & EPOLLHUP) && !(what & EPOLLRDHUP)) {
494 1.1 christos ev = EV_READ | EV_WRITE;
495 1.1 christos } else {
496 1.1 christos if (what & EPOLLIN)
497 1.1 christos ev |= EV_READ;
498 1.1 christos if (what & EPOLLOUT)
499 1.1 christos ev |= EV_WRITE;
500 1.2 christos if (what & EPOLLRDHUP)
501 1.2 christos ev |= EV_CLOSED;
502 1.1 christos }
503 1.1 christos
504 1.1 christos if (!ev)
505 1.1 christos continue;
506 1.1 christos
507 1.1 christos evmap_io_active_(base, events[i].data.fd, ev | EV_ET);
508 1.1 christos }
509 1.1 christos
510 1.1 christos if (res == epollop->nevents && epollop->nevents < MAX_NEVENT) {
511 1.1 christos /* We used all of the event space this time. We should
512 1.1 christos be ready for more events next time. */
513 1.1 christos int new_nevents = epollop->nevents * 2;
514 1.1 christos struct epoll_event *new_events;
515 1.1 christos
516 1.1 christos new_events = mm_realloc(epollop->events,
517 1.1 christos new_nevents * sizeof(struct epoll_event));
518 1.1 christos if (new_events) {
519 1.1 christos epollop->events = new_events;
520 1.1 christos epollop->nevents = new_nevents;
521 1.1 christos }
522 1.1 christos }
523 1.1 christos
524 1.1 christos return (0);
525 1.1 christos }
526 1.1 christos
527 1.1 christos
528 1.1 christos static void
529 1.1 christos epoll_dealloc(struct event_base *base)
530 1.1 christos {
531 1.1 christos struct epollop *epollop = base->evbase;
532 1.1 christos
533 1.1 christos evsig_dealloc_(base);
534 1.1 christos if (epollop->events)
535 1.1 christos mm_free(epollop->events);
536 1.1 christos if (epollop->epfd >= 0)
537 1.1 christos close(epollop->epfd);
538 1.1 christos #ifdef USING_TIMERFD
539 1.1 christos if (epollop->timerfd >= 0)
540 1.1 christos close(epollop->timerfd);
541 1.1 christos #endif
542 1.1 christos
543 1.1 christos memset(epollop, 0, sizeof(struct epollop));
544 1.1 christos mm_free(epollop);
545 1.1 christos }
546 1.1 christos
547 1.1 christos #endif /* EVENT__HAVE_EPOLL */
548