upstream nginx-0.7.31
[nginx.git] / nginx / src / event / modules / ngx_epoll_module.c
1
2 /*
3  * Copyright (C) Igor Sysoev
4  */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_event.h>
10
11
12 #if (NGX_TEST_BUILD_EPOLL)
13
14 /* epoll declarations */
15
16 #define EPOLLIN        0x001
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
26
27 #define EPOLLET        0x80000000
28 #define EPOLLONESHOT   0x40000000
29
30 #define EPOLL_CTL_ADD  1
31 #define EPOLL_CTL_DEL  2
32 #define EPOLL_CTL_MOD  3
33
34 typedef union epoll_data {
35     void         *ptr;
36     int           fd;
37     uint32_t      u32;
38     uint64_t      u64;
39 } epoll_data_t;
40
41 struct epoll_event {
42     uint32_t      events;
43     epoll_data_t  data;
44 };
45
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);
49
50 int epoll_create(int size)
51 {
52     return -1;
53 }
54
55 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
56 {
57     return -1;
58 }
59
60 int epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout)
61 {
62     return -1;
63 }
64
65 #endif
66
67
68 typedef struct {
69     ngx_uint_t  events;
70 } ngx_epoll_conf_t;
71
72
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,
76     ngx_uint_t flags);
77 static ngx_int_t ngx_epoll_del_event(ngx_event_t *ev, ngx_int_t event,
78     ngx_uint_t flags);
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,
81     ngx_uint_t flags);
82 static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
83     ngx_uint_t flags);
84
85 static void *ngx_epoll_create_conf(ngx_cycle_t *cycle);
86 static char *ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf);
87
88 static int                  ep = -1;
89 static struct epoll_event  *event_list;
90 static ngx_uint_t           nevents;
91
92
93 static ngx_str_t      epoll_name = ngx_string("epoll");
94
95 static ngx_command_t  ngx_epoll_commands[] = {
96
97     { ngx_string("epoll_events"),
98       NGX_EVENT_CONF|NGX_CONF_TAKE1,
99       ngx_conf_set_num_slot,
100       0,
101       offsetof(ngx_epoll_conf_t, events),
102       NULL },
103
104       ngx_null_command
105 };
106
107
108 ngx_event_module_t  ngx_epoll_module_ctx = {
109     &epoll_name,
110     ngx_epoll_create_conf,               /* create configuration */
111     ngx_epoll_init_conf,                 /* init configuration */
112
113     {
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 */
124     }
125 };
126
127 ngx_module_t  ngx_epoll_module = {
128     NGX_MODULE_V1,
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
140 };
141
142
143 static ngx_int_t
144 ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
145 {
146     ngx_epoll_conf_t  *epcf;
147
148     epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_module);
149
150     if (ep == -1) {
151         ep = epoll_create(cycle->connection_n / 2);
152
153         if (ep == -1) {
154             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
155                           "epoll_create() failed");
156             return NGX_ERROR;
157         }
158     }
159
160     if (nevents < epcf->events) {
161         if (event_list) {
162             ngx_free(event_list);
163         }
164
165         event_list = ngx_alloc(sizeof(struct epoll_event) * epcf->events,
166                                cycle->log);
167         if (event_list == NULL) {
168             return NGX_ERROR;
169         }
170     }
171
172     nevents = epcf->events;
173
174     ngx_io = ngx_os_io;
175
176     ngx_event_actions = ngx_epoll_module_ctx.actions;
177
178 #if (NGX_HAVE_CLEAR_EVENT)
179     ngx_event_flags = NGX_USE_CLEAR_EVENT
180 #else
181     ngx_event_flags = NGX_USE_LEVEL_EVENT
182 #endif
183                       |NGX_USE_GREEDY_EVENT
184                       |NGX_USE_EPOLL_EVENT;
185
186     return NGX_OK;
187 }
188
189
190 static void
191 ngx_epoll_done(ngx_cycle_t *cycle)
192 {
193     if (close(ep) == -1) {
194         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
195                       "epoll close() failed");
196     }
197
198     ep = -1;
199
200     ngx_free(event_list);
201
202     event_list = NULL;
203     nevents = 0;
204 }
205
206
207 static ngx_int_t
208 ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
209 {
210     int                  op;
211     uint32_t             events, prev;
212     ngx_event_t         *e;
213     ngx_connection_t    *c;
214     struct epoll_event   ee;
215
216     c = ev->data;
217
218     events = (uint32_t) event;
219
220     if (event == NGX_READ_EVENT) {
221         e = c->write;
222         prev = EPOLLOUT;
223 #if (NGX_READ_EVENT != EPOLLIN)
224         events = EPOLLIN;
225 #endif
226
227     } else {
228         e = c->read;
229         prev = EPOLLIN;
230 #if (NGX_WRITE_EVENT != EPOLLOUT)
231         events = EPOLLOUT;
232 #endif
233     }
234
235     if (e->active) {
236         op = EPOLL_CTL_MOD;
237         events |= prev;
238
239     } else {
240         op = EPOLL_CTL_ADD;
241     }
242
243     ee.events = events | (uint32_t) flags;
244     ee.data.ptr = (void *) ((uintptr_t) c | ev->instance);
245
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);
249
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);
253         return NGX_ERROR;
254     }
255
256     ev->active = 1;
257 #if 0
258     ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1 : 0;
259 #endif
260
261     return NGX_OK;
262 }
263
264
265 static ngx_int_t
266 ngx_epoll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
267 {
268     int                  op;
269     uint32_t             prev;
270     ngx_event_t         *e;
271     ngx_connection_t    *c;
272     struct epoll_event   ee;
273
274     /*
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
278      */
279
280     if (flags & NGX_CLOSE_EVENT) {
281         ev->active = 0;
282         return NGX_OK;
283     }
284
285     c = ev->data;
286
287     if (event == NGX_READ_EVENT) {
288         e = c->write;
289         prev = EPOLLOUT;
290
291     } else {
292         e = c->read;
293         prev = EPOLLIN;
294     }
295
296     if (e->active) {
297         op = EPOLL_CTL_MOD;
298         ee.events = prev | (uint32_t) flags;
299         ee.data.ptr = (void *) ((uintptr_t) c | ev->instance);
300
301     } else {
302         op = EPOLL_CTL_DEL;
303         ee.events = 0;
304         ee.data.ptr = NULL;
305     }
306
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);
310
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);
314         return NGX_ERROR;
315     }
316
317     ev->active = 0;
318
319     return NGX_OK;
320 }
321
322
323 static ngx_int_t
324 ngx_epoll_add_connection(ngx_connection_t *c)
325 {
326     struct epoll_event  ee;
327
328     ee.events = EPOLLIN|EPOLLOUT|EPOLLET;
329     ee.data.ptr = (void *) ((uintptr_t) c | c->read->instance);
330
331     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
332                    "epoll add connection: fd:%d ev:%08XD", c->fd, ee.events);
333
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);
337         return NGX_ERROR;
338     }
339
340     c->read->active = 1;
341     c->write->active = 1;
342
343     return NGX_OK;
344 }
345
346
347 static ngx_int_t
348 ngx_epoll_del_connection(ngx_connection_t *c, ngx_uint_t flags)
349 {
350     int                 op;
351     struct epoll_event  ee;
352
353     /*
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
357      */
358
359     if (flags & NGX_CLOSE_EVENT) {
360         c->read->active = 0;
361         c->write->active = 0;
362         return NGX_OK;
363     }
364
365     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
366                    "epoll del connection: fd:%d", c->fd);
367
368     op = EPOLL_CTL_DEL;
369     ee.events = 0;
370     ee.data.ptr = NULL;
371
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);
375         return NGX_ERROR;
376     }
377
378     c->read->active = 0;
379     c->write->active = 0;
380
381     return NGX_OK;
382 }
383
384
385 static ngx_int_t
386 ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
387 {
388     int                events;
389     uint32_t           revents;
390     ngx_int_t          instance, i;
391     ngx_uint_t         level;
392     ngx_err_t          err;
393     ngx_log_t         *log;
394     ngx_event_t       *rev, *wev, **queue;
395     ngx_connection_t  *c;
396
397     /* NGX_TIMER_INFINITE == INFTIM */
398
399     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
400                    "epoll timer: %M", timer);
401
402     events = epoll_wait(ep, event_list, (int) nevents, timer);
403
404     if (events == -1) {
405         err = ngx_errno;
406     } else {
407         err = 0;
408     }
409
410     if (flags & NGX_UPDATE_TIME) {
411         ngx_time_update(0, 0);
412     }
413
414     if (err) {
415         if (err == NGX_EINTR) {
416
417             if (ngx_event_timer_alarm) {
418                 ngx_event_timer_alarm = 0;
419                 return NGX_OK;
420             }
421
422             level = NGX_LOG_INFO;
423
424         } else {
425             level = NGX_LOG_ALERT;
426         }
427
428         ngx_log_error(level, cycle->log, err, "epoll_wait() failed");
429         return NGX_ERROR;
430     }
431
432     if (events == 0) {
433         if (timer != NGX_TIMER_INFINITE) {
434             return NGX_OK;
435         }
436
437         ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
438                       "epoll_wait() returned no events without timeout");
439         return NGX_ERROR;
440     }
441
442     ngx_mutex_lock(ngx_posted_events_mutex);
443
444     log = cycle->log;
445
446     for (i = 0; i < events; i++) {
447         c = event_list[i].data.ptr;
448
449         instance = (uintptr_t) c & 1;
450         c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);
451
452         rev = c->read;
453
454         if (c->fd == -1 || rev->instance != instance) {
455
456             /*
457              * the stale event from a file descriptor
458              * that was just closed in this iteration
459              */
460
461             ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
462                            "epoll: stale event %p", c);
463             continue;
464         }
465
466 #if (NGX_DEBUG0)
467         log = c->log ? c->log : cycle->log;
468 #endif
469
470         revents = event_list[i].events;
471
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);
475
476         if (revents & (EPOLLERR|EPOLLHUP)) {
477             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0,
478                            "epoll_wait() error on fd:%d ev:%04XD",
479                            c->fd, revents);
480         }
481
482 #if 0
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",
486                           c->fd, revents);
487         }
488 #endif
489
490         if ((revents & (EPOLLERR|EPOLLHUP))
491              && (revents & (EPOLLIN|EPOLLOUT)) == 0)
492         {
493             /*
494              * if the error events were returned without EPOLLIN or EPOLLOUT,
495              * then add these flags to handle the events at least in one
496              * active handler
497              */
498
499             revents |= EPOLLIN|EPOLLOUT;
500         }
501
502         if ((revents & EPOLLIN) && rev->active) {
503
504             if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
505                 rev->posted_ready = 1;
506
507             } else {
508                 rev->ready = 1;
509             }
510
511             if (flags & NGX_POST_EVENTS) {
512                 queue = (ngx_event_t **) (rev->accept ?
513                                &ngx_posted_accept_events : &ngx_posted_events);
514
515                 ngx_locked_post_event(rev, queue);
516
517             } else {
518                 rev->handler(rev);
519             }
520         }
521
522         wev = c->write;
523
524         if ((revents & EPOLLOUT) && wev->active) {
525
526             if (flags & NGX_POST_THREAD_EVENTS) {
527                 wev->posted_ready = 1;
528
529             } else {
530                 wev->ready = 1;
531             }
532
533             if (flags & NGX_POST_EVENTS) {
534                 ngx_locked_post_event(wev, &ngx_posted_events);
535
536             } else {
537                 wev->handler(wev);
538             }
539         }
540     }
541
542     ngx_mutex_unlock(ngx_posted_events_mutex);
543
544     return NGX_OK;
545 }
546
547
548 static void *
549 ngx_epoll_create_conf(ngx_cycle_t *cycle)
550 {
551     ngx_epoll_conf_t  *epcf;
552
553     epcf = ngx_palloc(cycle->pool, sizeof(ngx_epoll_conf_t));
554     if (epcf == NULL) {
555         return NGX_CONF_ERROR;
556     }
557
558     epcf->events = NGX_CONF_UNSET;
559
560     return epcf;
561 }
562
563
564 static char *
565 ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf)
566 {
567     ngx_epoll_conf_t *epcf = conf;
568
569     ngx_conf_init_uint_value(epcf->events, 512);
570
571     return NGX_CONF_OK;
572 }