Coverage Report

Created: 2025-07-11 06:22

/src/libevent/epoll.c
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
#if defined EVENT__HAVE_EPOLL || defined EVENT__HAVE_WEPOLL
31
32
#include <stdint.h>
33
#include <stdio.h>
34
#include <stdlib.h>
35
#include <limits.h>
36
#include <string.h>
37
38
#ifdef EVENT__HAVE_WEPOLL
39
#include "wepoll.h"
40
#define EPOLLET 0
41
#else
42
#include <sys/types.h>
43
#include <sys/resource.h>
44
#ifdef EVENT__HAVE_SYS_TIME_H
45
#include <sys/time.h>
46
#endif
47
#include <sys/queue.h>
48
#include <sys/epoll.h>
49
#include <signal.h>
50
#include <unistd.h>
51
#include <errno.h>
52
#ifdef EVENT__HAVE_FCNTL_H
53
#include <fcntl.h>
54
#endif
55
#ifdef EVENT__HAVE_SYS_TIMERFD_H
56
#include <sys/timerfd.h>
57
#endif
58
#endif
59
60
#include "event-internal.h"
61
#include "evsignal-internal.h"
62
#include "event2/thread.h"
63
#include "evthread-internal.h"
64
#include "log-internal.h"
65
#include "evmap-internal.h"
66
#include "changelist-internal.h"
67
#include "time-internal.h"
68
69
/* Since Linux 2.6.17, epoll is able to report about peer half-closed connection
70
   using special EPOLLRDHUP flag on a read event.
71
*/
72
#if !defined(EPOLLRDHUP)
73
#define EPOLLRDHUP 0
74
#define EARLY_CLOSE_IF_HAVE_RDHUP 0
75
#else
76
#define EARLY_CLOSE_IF_HAVE_RDHUP EV_FEATURE_EARLY_CLOSE
77
#endif
78
79
#include "epolltable-internal.h"
80
81
#if defined(EVENT__HAVE_SYS_TIMERFD_H) &&       \
82
  defined(EVENT__HAVE_TIMERFD_CREATE) &&        \
83
  defined(HAVE_POSIX_MONOTONIC) && defined(TFD_NONBLOCK) && \
84
  defined(TFD_CLOEXEC) && !defined(EVENT__HAVE_EPOLL_PWAIT2)
85
/* Note that we only use timerfd if TFD_NONBLOCK and TFD_CLOEXEC are available
86
   and working.  This means that we can't support it on 2.6.25 (where timerfd
87
   was introduced) or 2.6.26, since 2.6.27 introduced those flags. On recent
88
   enough systems (with 5.11 and never) and so epoll_pwait2() with nanosecond
89
   precision for timeouts, timerfd is not needed at all.
90
*/
91
#define USING_TIMERFD
92
#endif
93
94
#ifdef EVENT__HAVE_WEPOLL
95
typedef HANDLE epoll_handle;
96
#define INVALID_EPOLL_HANDLE NULL
97
static void close_epoll_handle(HANDLE h) { epoll_close(h); }
98
#else
99
typedef int epoll_handle;
100
14.1k
#define INVALID_EPOLL_HANDLE -1
101
4.71k
static void close_epoll_handle(int h) { close(h); }
102
#endif
103
104
struct epollop {
105
  struct epoll_event *events;
106
  int nevents;
107
  epoll_handle epfd;
108
#ifdef USING_TIMERFD
109
  int timerfd;
110
#endif
111
};
112
113
static void *epoll_init(struct event_base *);
114
static int epoll_dispatch(struct event_base *, struct timeval *);
115
static void epoll_dealloc(struct event_base *);
116
117
static const struct eventop epollops_changelist = {
118
  "epoll (with changelist)",
119
  epoll_init,
120
  event_changelist_add_,
121
  event_changelist_del_,
122
  epoll_dispatch,
123
  epoll_dealloc,
124
  1, /* need reinit */
125
  EV_FEATURE_ET|EV_FEATURE_O1| EARLY_CLOSE_IF_HAVE_RDHUP,
126
  EVENT_CHANGELIST_FDINFO_SIZE
127
};
128
129
130
static int epoll_nochangelist_add(struct event_base *base, evutil_socket_t fd,
131
    short old, short events, void *p);
132
static int epoll_nochangelist_del(struct event_base *base, evutil_socket_t fd,
133
    short old, short events, void *p);
134
135
#ifdef EVENT__HAVE_WEPOLL
136
const struct eventop wepollops = {
137
  "wepoll",
138
  epoll_init,
139
  epoll_nochangelist_add,
140
  epoll_nochangelist_del,
141
  epoll_dispatch,
142
  epoll_dealloc,
143
  1, /* need reinit */
144
  EV_FEATURE_O1|EV_FEATURE_EARLY_CLOSE,
145
  0
146
};
147
#else
148
const struct eventop epollops = {
149
  "epoll",
150
  epoll_init,
151
  epoll_nochangelist_add,
152
  epoll_nochangelist_del,
153
  epoll_dispatch,
154
  epoll_dealloc,
155
  1, /* need reinit */
156
  EV_FEATURE_ET|EV_FEATURE_O1|EV_FEATURE_EARLY_CLOSE,
157
  0
158
};
159
#endif
160
161
162
4.71k
#define INITIAL_NEVENT 32
163
0
#define MAX_NEVENT 4096
164
165
/* On Linux kernels at least up to 2.6.24.4, epoll can't handle timeout
166
 * values bigger than (LONG_MAX - 999ULL)/HZ.  HZ in the wild can be
167
 * as big as 1000, and LONG_MAX can be as small as (1<<31)-1, so the
168
 * largest number of msec we can support here is 2147482.  Let's
169
 * round that down by 47 seconds.
170
 */
171
0
#define MAX_EPOLL_TIMEOUT_MSEC (35*60*1000)
172
173
static void *
174
epoll_init(struct event_base *base)
175
4.71k
{
176
4.71k
  epoll_handle epfd = INVALID_EPOLL_HANDLE;
177
4.71k
  struct epollop *epollop;
178
179
4.71k
#ifdef EVENT__HAVE_EPOLL_CREATE1
180
  /* First, try the shiny new epoll_create1 interface, if we have it. */
181
4.71k
  epfd = epoll_create1(EPOLL_CLOEXEC);
182
4.71k
#endif
183
4.71k
  if (epfd == INVALID_EPOLL_HANDLE) {
184
    /* Initialize the kernel queue using the old interface.  (The
185
    size field is ignored   since 2.6.8.) */
186
0
    if ((epfd = epoll_create(32000)) == INVALID_EPOLL_HANDLE) {
187
0
      if (errno != ENOSYS)
188
0
        event_warn("epoll_create");
189
0
      return (NULL);
190
0
    }
191
0
#ifndef EVENT__HAVE_WEPOLL
192
0
    evutil_make_socket_closeonexec(epfd);
193
0
#endif
194
0
  }
195
196
4.71k
  if (!(epollop = mm_calloc(1, sizeof(struct epollop)))) {
197
0
    close_epoll_handle(epfd);
198
0
    return (NULL);
199
0
  }
200
201
4.71k
  epollop->epfd = epfd;
202
203
  /* Initialize fields */
204
4.71k
  epollop->events = mm_calloc(INITIAL_NEVENT, sizeof(struct epoll_event));
205
4.71k
  if (epollop->events == NULL) {
206
0
    mm_free(epollop);
207
0
    close_epoll_handle(epfd);
208
0
    return (NULL);
209
0
  }
210
4.71k
  epollop->nevents = INITIAL_NEVENT;
211
212
4.71k
#ifndef EVENT__HAVE_WEPOLL
213
4.71k
  if ((base->flags & EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST) != 0 ||
214
4.71k
      ((base->flags & EVENT_BASE_FLAG_IGNORE_ENV) == 0 &&
215
4.71k
    evutil_getenv_("EVENT_EPOLL_USE_CHANGELIST") != NULL)) {
216
217
0
    base->evsel = &epollops_changelist;
218
0
  }
219
4.71k
#endif
220
221
4.71k
#ifdef USING_TIMERFD
222
  /*
223
    The epoll interface ordinarily gives us one-millisecond precision,
224
    so on Linux it makes perfect sense to use the CLOCK_MONOTONIC_COARSE
225
    timer.  But when the user has set the new PRECISE_TIMER flag for an
226
    event_base, we can try to use timerfd to give them finer granularity.
227
  */
228
4.71k
  if ((base->flags & EVENT_BASE_FLAG_PRECISE_TIMER) &&
229
4.71k
      !(base->flags & EVENT_BASE_FLAG_EPOLL_DISALLOW_TIMERFD) &&
230
4.71k
      base->monotonic_timer.monotonic_clock == CLOCK_MONOTONIC) {
231
0
    int fd;
232
0
    fd = epollop->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC);
233
0
    if (epollop->timerfd >= 0) {
234
0
      struct epoll_event epev;
235
0
      memset(&epev, 0, sizeof(epev));
236
0
      epev.data.fd = epollop->timerfd;
237
0
      epev.events = EPOLLIN;
238
0
      if (epoll_ctl(epollop->epfd, EPOLL_CTL_ADD, fd, &epev) < 0) {
239
0
        event_warn("epoll_ctl(timerfd)");
240
0
        close(fd);
241
0
        epollop->timerfd = -1;
242
0
      }
243
0
    } else {
244
0
      if (errno != EINVAL && errno != ENOSYS) {
245
        /* These errors probably mean that we were
246
         * compiled with timerfd/TFD_* support, but
247
         * we're running on a kernel that lacks those.
248
         */
249
0
        event_warn("timerfd_create");
250
0
      }
251
0
      epollop->timerfd = -1;
252
0
    }
253
4.71k
  } else {
254
4.71k
    epollop->timerfd = -1;
255
4.71k
  }
256
4.71k
#endif
257
258
4.71k
  if (sigfd_init_(base) < 0)
259
4.71k
    evsig_init_(base);
260
261
4.71k
  return (epollop);
262
4.71k
}
263
264
static const char *
265
change_to_string(int change)
266
0
{
267
0
  change &= (EV_CHANGE_ADD|EV_CHANGE_DEL);
268
0
  if (change == EV_CHANGE_ADD) {
269
0
    return "add";
270
0
  } else if (change == EV_CHANGE_DEL) {
271
0
    return "del";
272
0
  } else if (change == 0) {
273
0
    return "none";
274
0
  } else {
275
0
    return "???";
276
0
  }
277
0
}
278
279
static const char *
280
epoll_op_to_string(int op)
281
0
{
282
0
  return op == EPOLL_CTL_ADD?"ADD":
283
0
      op == EPOLL_CTL_DEL?"DEL":
284
0
      op == EPOLL_CTL_MOD?"MOD":
285
0
      "???";
286
0
}
287
288
#define PRINT_CHANGES(op, events, ch, status)  \
289
0
  "Epoll %s(%d) on fd %d " status ". "       \
290
0
  "Old events were %d; "                     \
291
0
  "read change was %d (%s); "                \
292
0
  "write change was %d (%s); "               \
293
0
  "close change was %d (%s)",                \
294
0
  epoll_op_to_string(op),                    \
295
0
  events,                                    \
296
0
  ch->fd,                                    \
297
0
  ch->old_events,                            \
298
0
  ch->read_change,                           \
299
0
  change_to_string(ch->read_change),         \
300
0
  ch->write_change,                          \
301
0
  change_to_string(ch->write_change),        \
302
0
  ch->close_change,                          \
303
0
  change_to_string(ch->close_change)
304
305
static int
306
epoll_apply_one_change(struct event_base *base,
307
    struct epollop *epollop,
308
    const struct event_change *ch)
309
21.2k
{
310
21.2k
  struct epoll_event epev;
311
21.2k
  int op, events = 0;
312
21.2k
  int idx;
313
314
21.2k
  idx = EPOLL_OP_TABLE_INDEX(ch);
315
21.2k
  op = epoll_op_table[idx].op;
316
21.2k
  events = epoll_op_table[idx].events;
317
318
21.2k
  if (!events) {
319
0
    EVUTIL_ASSERT(op == 0);
320
0
    return 0;
321
0
  }
322
323
21.2k
  if ((ch->read_change|ch->write_change|ch->close_change) & EV_CHANGE_ET)
324
0
    events |= EPOLLET;
325
326
21.2k
  memset(&epev, 0, sizeof(epev));
327
#ifdef EVENT__HAVE_WEPOLL
328
  epev.data.sock = ch->fd;
329
#else
330
21.2k
  epev.data.fd = ch->fd;
331
21.2k
#endif
332
21.2k
  epev.events = events;
333
21.2k
  if (epoll_ctl(epollop->epfd, op, ch->fd, &epev) == 0) {
334
10.6k
    event_debug((PRINT_CHANGES(op, epev.events, ch, "okay")));
335
10.6k
    return 0;
336
10.6k
  }
337
338
10.6k
  switch (op) {
339
0
  case EPOLL_CTL_MOD:
340
0
    if (errno == ENOENT) {
341
      /* If a MOD operation fails with ENOENT, the
342
       * fd was probably closed and re-opened.  We
343
       * should retry the operation as an ADD.
344
       */
345
0
      if (epoll_ctl(epollop->epfd, EPOLL_CTL_ADD, ch->fd, &epev) == -1) {
346
0
        event_warn("Epoll MOD(%d) on %d retried as ADD; that failed too",
347
0
            (int)epev.events, ch->fd);
348
0
        return -1;
349
0
      } else {
350
0
        event_debug(("Epoll MOD(%d) on %d retried as ADD; succeeded.",
351
0
          (int)epev.events,
352
0
          ch->fd));
353
0
        return 0;
354
0
      }
355
0
    }
356
0
    break;
357
0
  case EPOLL_CTL_ADD:
358
0
    if (errno == EEXIST) {
359
      /* If an ADD operation fails with EEXIST,
360
       * either the operation was redundant (as with a
361
       * precautionary add), or we ran into a fun
362
       * kernel bug where using dup*() to duplicate the
363
       * same file into the same fd gives you the same epitem
364
       * rather than a fresh one.  For the second case,
365
       * we must retry with MOD. */
366
0
      if (epoll_ctl(epollop->epfd, EPOLL_CTL_MOD, ch->fd, &epev) == -1) {
367
0
        event_warn("Epoll ADD(%d) on %d retried as MOD; that failed too",
368
0
            (int)epev.events, ch->fd);
369
0
        return -1;
370
0
      } else {
371
0
        event_debug(("Epoll ADD(%d) on %d retried as MOD; succeeded.",
372
0
          (int)epev.events,
373
0
          ch->fd));
374
0
        return 0;
375
0
      }
376
0
    }
377
0
    break;
378
10.6k
  case EPOLL_CTL_DEL:
379
10.6k
    if (errno == ENOENT || errno == EBADF || errno == EPERM) {
380
      /* If a delete fails with one of these errors,
381
       * that's fine too: we closed the fd before we
382
       * got around to calling epoll_dispatch. */
383
10.6k
      event_debug(("Epoll DEL(%d) on fd %d gave %s: DEL was unnecessary.",
384
10.6k
        (int)epev.events,
385
10.6k
        ch->fd,
386
10.6k
        strerror(errno)));
387
10.6k
      return 0;
388
10.6k
    }
389
0
    break;
390
0
  default:
391
0
    break;
392
10.6k
  }
393
394
0
  event_warn(PRINT_CHANGES(op, epev.events, ch, "failed"));
395
0
  return -1;
396
10.6k
}
397
398
static int
399
epoll_apply_changes(struct event_base *base)
400
0
{
401
0
  struct event_changelist *changelist = &base->changelist;
402
0
  struct epollop *epollop = base->evbase;
403
0
  struct event_change *ch;
404
405
0
  int r = 0;
406
0
  int i;
407
408
0
  for (i = 0; i < changelist->n_changes; ++i) {
409
0
    ch = &changelist->changes[i];
410
0
    if (epoll_apply_one_change(base, epollop, ch) < 0)
411
0
      r = -1;
412
0
  }
413
414
0
  return (r);
415
0
}
416
417
static int
418
epoll_nochangelist_add(struct event_base *base, evutil_socket_t fd,
419
    short old, short events, void *p)
420
10.6k
{
421
10.6k
  struct event_change ch;
422
10.6k
  ch.fd = fd;
423
10.6k
  ch.old_events = old;
424
10.6k
  ch.read_change = ch.write_change = ch.close_change = 0;
425
10.6k
  if (events & EV_WRITE)
426
0
    ch.write_change = EV_CHANGE_ADD |
427
0
        (events & EV_ET);
428
10.6k
  if (events & EV_READ)
429
10.6k
    ch.read_change = EV_CHANGE_ADD |
430
10.6k
        (events & EV_ET);
431
10.6k
  if (events & EV_CLOSED)
432
0
    ch.close_change = EV_CHANGE_ADD |
433
0
        (events & EV_ET);
434
435
10.6k
  return epoll_apply_one_change(base, base->evbase, &ch);
436
10.6k
}
437
438
static int
439
epoll_nochangelist_del(struct event_base *base, evutil_socket_t fd,
440
    short old, short events, void *p)
441
10.6k
{
442
10.6k
  struct event_change ch;
443
10.6k
  ch.fd = fd;
444
10.6k
  ch.old_events = old;
445
10.6k
  ch.read_change = ch.write_change = ch.close_change = 0;
446
10.6k
  if (events & EV_WRITE)
447
0
    ch.write_change = EV_CHANGE_DEL |
448
0
        (events & EV_ET);
449
10.6k
  if (events & EV_READ)
450
10.6k
    ch.read_change = EV_CHANGE_DEL |
451
10.6k
        (events & EV_ET);
452
10.6k
  if (events & EV_CLOSED)
453
0
    ch.close_change = EV_CHANGE_DEL |
454
0
        (events & EV_ET);
455
456
10.6k
  return epoll_apply_one_change(base, base->evbase, &ch);
457
10.6k
}
458
459
static int
460
epoll_dispatch(struct event_base *base, struct timeval *tv)
461
0
{
462
0
  struct epollop *epollop = base->evbase;
463
0
  struct epoll_event *events = epollop->events;
464
0
  int i, res;
465
#if defined(EVENT__HAVE_EPOLL_PWAIT2)
466
  struct timespec ts = { 0, 0 };
467
#else /* no epoll_pwait2() */
468
0
  long timeout = -1;
469
0
#endif /* EVENT__HAVE_EPOLL_PWAIT2 */
470
471
0
#ifdef USING_TIMERFD
472
0
  if (epollop->timerfd >= 0) {
473
0
    struct itimerspec is;
474
0
    is.it_interval.tv_sec = 0;
475
0
    is.it_interval.tv_nsec = 0;
476
0
    if (tv == NULL) {
477
      /* No timeout; disarm the timer. */
478
0
      is.it_value.tv_sec = 0;
479
0
      is.it_value.tv_nsec = 0;
480
0
    } else {
481
0
      if (tv->tv_sec == 0 && tv->tv_usec == 0) {
482
        /* we need to exit immediately; timerfd can't
483
         * do that. */
484
0
        timeout = 0;
485
0
      }
486
0
      is.it_value.tv_sec = tv->tv_sec;
487
0
      is.it_value.tv_nsec = tv->tv_usec * 1000;
488
0
    }
489
    /* TODO: we could avoid unnecessary syscalls here by only
490
       calling timerfd_settime when the top timeout changes, or
491
       when we're called with a different timeval.
492
    */
493
0
    if (timerfd_settime(epollop->timerfd, 0, &is, NULL) < 0) {
494
0
      event_warn("timerfd_settime");
495
0
    }
496
0
  } else
497
0
#endif
498
0
  if (tv != NULL) {
499
#if defined(EVENT__HAVE_EPOLL_PWAIT2)
500
    TIMEVAL_TO_TIMESPEC(tv, &ts);
501
#else /* no epoll_pwait2() */
502
0
    timeout = evutil_tv_to_msec_(tv);
503
0
    if (timeout < 0 || timeout > MAX_EPOLL_TIMEOUT_MSEC) {
504
      /* Linux kernels can wait forever if the timeout is
505
       * too big; see comment on MAX_EPOLL_TIMEOUT_MSEC. */
506
0
      timeout = MAX_EPOLL_TIMEOUT_MSEC;
507
0
    }
508
0
#endif /* EVENT__HAVE_EPOLL_PWAIT2 */
509
0
  }
510
511
0
  epoll_apply_changes(base);
512
0
  event_changelist_remove_all_(&base->changelist, base);
513
514
0
  EVBASE_RELEASE_LOCK(base, th_base_lock);
515
516
#if defined(EVENT__HAVE_EPOLL_PWAIT2)
517
  res = epoll_pwait2(epollop->epfd, events, epollop->nevents, tv ? &ts : NULL, NULL);
518
#else /* no epoll_pwait2() */
519
0
  res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);
520
0
#endif /* EVENT__HAVE_EPOLL_PWAIT2 */
521
522
0
  EVBASE_ACQUIRE_LOCK(base, th_base_lock);
523
524
0
  if (res == -1) {
525
0
    if (errno != EINTR) {
526
0
      event_warn("epoll_wait");
527
0
      return (-1);
528
0
    }
529
530
0
    return (0);
531
0
  }
532
533
0
  event_debug(("%s: epoll_wait reports %d", __func__, res));
534
0
  EVUTIL_ASSERT(res <= epollop->nevents);
535
536
0
  for (i = 0; i < res; i++) {
537
0
    int what = events[i].events;
538
0
    short ev = 0;
539
0
#ifdef USING_TIMERFD
540
0
    if (events[i].data.fd == epollop->timerfd)
541
0
      continue;
542
0
#endif
543
544
0
    if (what & EPOLLERR) {
545
0
      ev = EV_READ | EV_WRITE;
546
0
    } else if ((what & EPOLLHUP) && !(what & EPOLLRDHUP)) {
547
0
      ev = EV_READ | EV_WRITE;
548
0
    } else {
549
0
      if (what & EPOLLIN)
550
0
        ev |= EV_READ;
551
0
      if (what & EPOLLOUT)
552
0
        ev |= EV_WRITE;
553
0
      if (what & EPOLLRDHUP)
554
0
        ev |= EV_CLOSED;
555
0
    }
556
557
0
    if (!ev)
558
0
      continue;
559
560
#ifdef EVENT__HAVE_WEPOLL
561
    evmap_io_active_(base, events[i].data.sock, ev);
562
#else
563
0
    evmap_io_active_(base, events[i].data.fd, ev | EV_ET);
564
0
#endif
565
0
  }
566
567
0
  if (res == epollop->nevents && epollop->nevents < MAX_NEVENT) {
568
    /* We used all of the event space this time.  We should
569
       be ready for more events next time. */
570
0
    int new_nevents = epollop->nevents * 2;
571
0
    struct epoll_event *new_events;
572
573
0
    new_events = mm_realloc(epollop->events,
574
0
        new_nevents * sizeof(struct epoll_event));
575
0
    if (new_events) {
576
0
      epollop->events = new_events;
577
0
      epollop->nevents = new_nevents;
578
0
    }
579
0
  }
580
581
0
  return (0);
582
0
}
583
584
585
static void
586
epoll_dealloc(struct event_base *base)
587
4.71k
{
588
4.71k
  struct epollop *epollop = base->evbase;
589
590
4.71k
  evsig_dealloc_(base);
591
4.71k
  if (epollop->events)
592
4.71k
    mm_free(epollop->events);
593
4.71k
  if (epollop->epfd != INVALID_EPOLL_HANDLE)
594
4.71k
    close_epoll_handle(epollop->epfd);
595
4.71k
#ifdef USING_TIMERFD
596
4.71k
  if (epollop->timerfd >= 0)
597
0
    close(epollop->timerfd);
598
4.71k
#endif
599
600
4.71k
  memset(epollop, 0, sizeof(struct epollop));
601
4.71k
  mm_free(epollop);
602
4.71k
}
603
604
#endif /* defined EVENT__HAVE_EPOLL || defined EVENT__HAVE_WEPOLL */