3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
12 #if (NGX_TEST_BUILD_EPOLL)
14 /* epoll declarations */
17 #define EPOLLPRI 0x002
18 #define EPOLLOUT 0x004
19 #define EPOLLRDNORM 0x040
20 #define EPOLLRDBAND 0x080
21 #define EPOLLWRNORM 0x100
22 #define EPOLLWRBAND 0x200
23 #define EPOLLMSG 0x400
24 #define EPOLLERR 0x008
25 #define EPOLLHUP 0x010
27 #define EPOLLET 0x80000000
28 #define EPOLLONESHOT 0x40000000
30 #define EPOLL_CTL_ADD 1
31 #define EPOLL_CTL_DEL 2
32 #define EPOLL_CTL_MOD 3
34 typedef union epoll_data {
46 int epoll_create(int size);
47 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
48 int epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout);
50 int epoll_create(int size)
55 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
60 int epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout)
73 static ngx_int_t ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer);
74 static void ngx_epoll_done(ngx_cycle_t *cycle);
75 static ngx_int_t ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event,
77 static ngx_int_t ngx_epoll_del_event(ngx_event_t *ev, ngx_int_t event,
79 static ngx_int_t ngx_epoll_add_connection(ngx_connection_t *c);
80 static ngx_int_t ngx_epoll_del_connection(ngx_connection_t *c,
82 static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
85 static void *ngx_epoll_create_conf(ngx_cycle_t *cycle);
86 static char *ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf);
89 static struct epoll_event *event_list;
90 static ngx_uint_t nevents;
93 static ngx_str_t epoll_name = ngx_string("epoll");
95 static ngx_command_t ngx_epoll_commands[] = {
97 { ngx_string("epoll_events"),
98 NGX_EVENT_CONF|NGX_CONF_TAKE1,
99 ngx_conf_set_num_slot,
101 offsetof(ngx_epoll_conf_t, events),
108 ngx_event_module_t ngx_epoll_module_ctx = {
110 ngx_epoll_create_conf, /* create configuration */
111 ngx_epoll_init_conf, /* init configuration */
114 ngx_epoll_add_event, /* add an event */
115 ngx_epoll_del_event, /* delete an event */
116 ngx_epoll_add_event, /* enable an event */
117 ngx_epoll_del_event, /* disable an event */
118 ngx_epoll_add_connection, /* add an connection */
119 ngx_epoll_del_connection, /* delete an connection */
120 NULL, /* process the changes */
121 ngx_epoll_process_events, /* process the events */
122 ngx_epoll_init, /* init the events */
123 ngx_epoll_done, /* done the events */
127 ngx_module_t ngx_epoll_module = {
129 &ngx_epoll_module_ctx, /* module context */
130 ngx_epoll_commands, /* module directives */
131 NGX_EVENT_MODULE, /* module type */
132 NULL, /* init master */
133 NULL, /* init module */
134 NULL, /* init process */
135 NULL, /* init thread */
136 NULL, /* exit thread */
137 NULL, /* exit process */
138 NULL, /* exit master */
139 NGX_MODULE_V1_PADDING
144 ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
146 ngx_epoll_conf_t *epcf;
148 epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_module);
151 ep = epoll_create(cycle->connection_n / 2);
154 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
155 "epoll_create() failed");
160 if (nevents < epcf->events) {
162 ngx_free(event_list);
165 event_list = ngx_alloc(sizeof(struct epoll_event) * epcf->events,
167 if (event_list == NULL) {
172 nevents = epcf->events;
176 ngx_event_actions = ngx_epoll_module_ctx.actions;
178 #if (NGX_HAVE_CLEAR_EVENT)
179 ngx_event_flags = NGX_USE_CLEAR_EVENT
181 ngx_event_flags = NGX_USE_LEVEL_EVENT
183 |NGX_USE_GREEDY_EVENT
184 |NGX_USE_EPOLL_EVENT;
191 ngx_epoll_done(ngx_cycle_t *cycle)
193 if (close(ep) == -1) {
194 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
195 "epoll close() failed");
200 ngx_free(event_list);
208 ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
211 uint32_t events, prev;
214 struct epoll_event ee;
218 events = (uint32_t) event;
220 if (event == NGX_READ_EVENT) {
223 #if (NGX_READ_EVENT != EPOLLIN)
230 #if (NGX_WRITE_EVENT != EPOLLOUT)
243 ee.events = events | (uint32_t) flags;
244 ee.data.ptr = (void *) ((uintptr_t) c | ev->instance);
246 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
247 "epoll add event: fd:%d op:%d ev:%08XD",
248 c->fd, op, ee.events);
250 if (epoll_ctl(ep, op, c->fd, &ee) == -1) {
251 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
252 "epoll_ctl(%d, %d) failed", op, c->fd);
258 ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1 : 0;
266 ngx_epoll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
272 struct epoll_event ee;
275 * when the file descriptor is closed, the epoll automatically deletes
276 * it from its queue, so we do not need to delete explicity the event
277 * before the closing the file descriptor
280 if (flags & NGX_CLOSE_EVENT) {
287 if (event == NGX_READ_EVENT) {
298 ee.events = prev | (uint32_t) flags;
299 ee.data.ptr = (void *) ((uintptr_t) c | ev->instance);
307 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
308 "epoll del event: fd:%d op:%d ev:%08XD",
309 c->fd, op, ee.events);
311 if (epoll_ctl(ep, op, c->fd, &ee) == -1) {
312 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
313 "epoll_ctl(%d, %d) failed", op, c->fd);
324 ngx_epoll_add_connection(ngx_connection_t *c)
326 struct epoll_event ee;
328 ee.events = EPOLLIN|EPOLLOUT|EPOLLET;
329 ee.data.ptr = (void *) ((uintptr_t) c | c->read->instance);
331 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
332 "epoll add connection: fd:%d ev:%08XD", c->fd, ee.events);
334 if (epoll_ctl(ep, EPOLL_CTL_ADD, c->fd, &ee) == -1) {
335 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
336 "epoll_ctl(EPOLL_CTL_ADD, %d) failed", c->fd);
341 c->write->active = 1;
348 ngx_epoll_del_connection(ngx_connection_t *c, ngx_uint_t flags)
351 struct epoll_event ee;
354 * when the file descriptor is closed the epoll automatically deletes
355 * it from its queue so we do not need to delete explicity the event
356 * before the closing the file descriptor
359 if (flags & NGX_CLOSE_EVENT) {
361 c->write->active = 0;
365 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
366 "epoll del connection: fd:%d", c->fd);
372 if (epoll_ctl(ep, op, c->fd, &ee) == -1) {
373 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
374 "epoll_ctl(%d, %d) failed", op, c->fd);
379 c->write->active = 0;
386 ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
390 ngx_int_t instance, i;
394 ngx_event_t *rev, *wev, **queue;
397 /* NGX_TIMER_INFINITE == INFTIM */
399 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
400 "epoll timer: %M", timer);
402 events = epoll_wait(ep, event_list, (int) nevents, timer);
410 if (flags & NGX_UPDATE_TIME) {
411 ngx_time_update(0, 0);
415 if (err == NGX_EINTR) {
417 if (ngx_event_timer_alarm) {
418 ngx_event_timer_alarm = 0;
422 level = NGX_LOG_INFO;
425 level = NGX_LOG_ALERT;
428 ngx_log_error(level, cycle->log, err, "epoll_wait() failed");
433 if (timer != NGX_TIMER_INFINITE) {
437 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
438 "epoll_wait() returned no events without timeout");
442 ngx_mutex_lock(ngx_posted_events_mutex);
446 for (i = 0; i < events; i++) {
447 c = event_list[i].data.ptr;
449 instance = (uintptr_t) c & 1;
450 c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);
454 if (c->fd == -1 || rev->instance != instance) {
457 * the stale event from a file descriptor
458 * that was just closed in this iteration
461 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
462 "epoll: stale event %p", c);
467 log = c->log ? c->log : cycle->log;
470 revents = event_list[i].events;
472 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0,
473 "epoll: fd:%d ev:%04XD d:%p",
474 c->fd, revents, event_list[i].data.ptr);
476 if (revents & (EPOLLERR|EPOLLHUP)) {
477 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0,
478 "epoll_wait() error on fd:%d ev:%04XD",
483 if (revents & ~(EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP)) {
484 ngx_log_error(NGX_LOG_ALERT, log, 0,
485 "strange epoll_wait() events fd:%d ev:%04XD",
490 if ((revents & (EPOLLERR|EPOLLHUP))
491 && (revents & (EPOLLIN|EPOLLOUT)) == 0)
494 * if the error events were returned without EPOLLIN or EPOLLOUT,
495 * then add these flags to handle the events at least in one
499 revents |= EPOLLIN|EPOLLOUT;
502 if ((revents & EPOLLIN) && rev->active) {
504 if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
505 rev->posted_ready = 1;
511 if (flags & NGX_POST_EVENTS) {
512 queue = (ngx_event_t **) (rev->accept ?
513 &ngx_posted_accept_events : &ngx_posted_events);
515 ngx_locked_post_event(rev, queue);
524 if ((revents & EPOLLOUT) && wev->active) {
526 if (flags & NGX_POST_THREAD_EVENTS) {
527 wev->posted_ready = 1;
533 if (flags & NGX_POST_EVENTS) {
534 ngx_locked_post_event(wev, &ngx_posted_events);
542 ngx_mutex_unlock(ngx_posted_events_mutex);
549 ngx_epoll_create_conf(ngx_cycle_t *cycle)
551 ngx_epoll_conf_t *epcf;
553 epcf = ngx_palloc(cycle->pool, sizeof(ngx_epoll_conf_t));
555 return NGX_CONF_ERROR;
558 epcf->events = NGX_CONF_UNSET;
565 ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf)
567 ngx_epoll_conf_t *epcf = conf;
569 ngx_conf_init_uint_value(epcf->events, 512);