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