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