comparison src/event/modules/ngx_epoll_module.c @ 0:f0b350454894 NGINX_0_1_0

nginx 0.1.0 *) The first public version.
author Igor Sysoev <http://sysoev.ru>
date Mon, 04 Oct 2004 00:00:00 +0400
parents
children 4b2dafa26fe2
comparison
equal deleted inserted replaced
-1:000000000000 0:f0b350454894
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 (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 u_int events;
70 } ngx_epoll_conf_t;
71
72
73 static int ngx_epoll_init(ngx_cycle_t *cycle);
74 static void ngx_epoll_done(ngx_cycle_t *cycle);
75 static int ngx_epoll_add_event(ngx_event_t *ev, int event, u_int flags);
76 static int ngx_epoll_del_event(ngx_event_t *ev, int event, u_int flags);
77 static int ngx_epoll_add_connection(ngx_connection_t *c);
78 static int ngx_epoll_del_connection(ngx_connection_t *c, u_int flags);
79 static int ngx_epoll_process_events(ngx_cycle_t *cycle);
80
81 static void *ngx_epoll_create_conf(ngx_cycle_t *cycle);
82 static char *ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf);
83
84 static int ep = -1;
85 static struct epoll_event *event_list;
86 static u_int nevents;
87
88
89 static ngx_str_t epoll_name = ngx_string("epoll");
90
91 static ngx_command_t ngx_epoll_commands[] = {
92
93 {ngx_string("epoll_events"),
94 NGX_EVENT_CONF|NGX_CONF_TAKE1,
95 ngx_conf_set_num_slot,
96 0,
97 offsetof(ngx_epoll_conf_t, events),
98 NULL},
99
100 ngx_null_command
101 };
102
103
104 ngx_event_module_t ngx_epoll_module_ctx = {
105 &epoll_name,
106 ngx_epoll_create_conf, /* create configuration */
107 ngx_epoll_init_conf, /* init configuration */
108
109 {
110 ngx_epoll_add_event, /* add an event */
111 ngx_epoll_del_event, /* delete an event */
112 ngx_epoll_add_event, /* enable an event */
113 ngx_epoll_del_event, /* disable an event */
114 ngx_epoll_add_connection, /* add an connection */
115 ngx_epoll_del_connection, /* delete an connection */
116 NULL, /* process the changes */
117 ngx_epoll_process_events, /* process the events */
118 ngx_epoll_init, /* init the events */
119 ngx_epoll_done, /* done the events */
120 }
121 };
122
123 ngx_module_t ngx_epoll_module = {
124 NGX_MODULE,
125 &ngx_epoll_module_ctx, /* module context */
126 ngx_epoll_commands, /* module directives */
127 NGX_EVENT_MODULE, /* module type */
128 NULL, /* init module */
129 NULL /* init process */
130 };
131
132
133 static int ngx_epoll_init(ngx_cycle_t *cycle)
134 {
135 size_t n;
136 ngx_event_conf_t *ecf;
137 ngx_epoll_conf_t *epcf;
138
139 ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
140
141 epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_module);
142
143 if (ep == -1) {
144 ep = epoll_create(ecf->connections / 2);
145
146 if (ep == -1) {
147 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
148 "epoll_create() failed");
149 return NGX_ERROR;
150 }
151 }
152
153 if (nevents < epcf->events) {
154 if (event_list) {
155 ngx_free(event_list);
156 }
157
158 event_list = ngx_alloc(sizeof(struct epoll_event) * epcf->events,
159 cycle->log);
160 if (event_list == NULL) {
161 return NGX_ERROR;
162 }
163 }
164
165 nevents = epcf->events;
166
167 ngx_io = ngx_os_io;
168
169 ngx_event_actions = ngx_epoll_module_ctx.actions;
170
171 #if (HAVE_CLEAR_EVENT)
172 ngx_event_flags = NGX_USE_CLEAR_EVENT
173 #else
174 ngx_event_flags = NGX_USE_LEVEL_EVENT
175 #endif
176 |NGX_HAVE_GREEDY_EVENT
177 |NGX_USE_EPOLL_EVENT;
178
179 return NGX_OK;
180 }
181
182
183 static void ngx_epoll_done(ngx_cycle_t *cycle)
184 {
185 if (close(ep) == -1) {
186 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
187 "epoll close() failed");
188 }
189
190 ep = -1;
191
192 ngx_free(event_list);
193
194 event_list = NULL;
195 nevents = 0;
196 }
197
198
199 static int ngx_epoll_add_event(ngx_event_t *ev, int event, u_int flags)
200 {
201 int op, prev;
202 ngx_event_t *e;
203 ngx_connection_t *c;
204 struct epoll_event ee;
205
206 c = ev->data;
207
208 if (event == NGX_READ_EVENT) {
209 e = c->write;
210 prev = EPOLLOUT;
211 #if (NGX_READ_EVENT != EPOLLIN)
212 event = EPOLLIN;
213 #endif
214
215 } else {
216 e = c->read;
217 prev = EPOLLIN;
218 #if (NGX_WRITE_EVENT != EPOLLOUT)
219 event = EPOLLOUT;
220 #endif
221 }
222
223 if (e->active) {
224 op = EPOLL_CTL_MOD;
225 event |= prev;
226
227 } else {
228 op = EPOLL_CTL_ADD;
229 }
230
231 ee.events = event | flags;
232 ee.data.ptr = (void *) ((uintptr_t) c | ev->instance);
233
234 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
235 "epoll add event: fd:%d op:%d ev:%08X",
236 c->fd, op, ee.events);
237
238 if (epoll_ctl(ep, op, c->fd, &ee) == -1) {
239 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
240 "epoll_ctl(%d, %d) failed", op, c->fd);
241 return NGX_ERROR;
242 }
243
244 ev->active = 1;
245 #if 0
246 ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1 : 0;
247 #endif
248
249 return NGX_OK;
250 }
251
252
253 static int ngx_epoll_del_event(ngx_event_t *ev, int event, u_int flags)
254 {
255 int op, prev;
256 ngx_event_t *e;
257 ngx_connection_t *c;
258 struct epoll_event ee;
259
260 /*
261 * when the file descriptor is closed the epoll automatically deletes
262 * it from its queue so we do not need to delete explicity the event
263 * before the closing the file descriptor
264 */
265
266 if (flags & NGX_CLOSE_EVENT) {
267 ev->active = 0;
268 return NGX_OK;
269 }
270
271 c = ev->data;
272
273 if (event == NGX_READ_EVENT) {
274 e = c->write;
275 prev = EPOLLOUT;
276
277 } else {
278 e = c->read;
279 prev = EPOLLIN;
280 }
281
282 if (e->active) {
283 op = EPOLL_CTL_MOD;
284 ee.events = prev | flags;
285 ee.data.ptr = (void *) ((uintptr_t) c | ev->instance);
286
287 } else {
288 op = EPOLL_CTL_DEL;
289 ee.events = 0;
290 ee.data.ptr = NULL;
291 }
292
293 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
294 "epoll del event: fd:%d op:%d ev:%08X",
295 c->fd, op, ee.events);
296
297 if (epoll_ctl(ep, op, c->fd, &ee) == -1) {
298 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
299 "epoll_ctl(%d, %d) failed", op, c->fd);
300 return NGX_ERROR;
301 }
302
303 ev->active = 0;
304
305 return NGX_OK;
306 }
307
308
309 static int ngx_epoll_add_connection(ngx_connection_t *c)
310 {
311 struct epoll_event ee;
312
313 ee.events = EPOLLIN|EPOLLOUT|EPOLLET;
314 ee.data.ptr = (void *) ((uintptr_t) c | c->read->instance);
315
316 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
317 "epoll add connection: fd:%d ev:%08X", c->fd, ee.events);
318
319 if (epoll_ctl(ep, EPOLL_CTL_ADD, c->fd, &ee) == -1) {
320 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
321 "epoll_ctl(EPOLL_CTL_ADD, %d) failed", c->fd);
322 return NGX_ERROR;
323 }
324
325 c->read->active = 1;
326 c->write->active = 1;
327
328 return NGX_OK;
329 }
330
331
332 static int ngx_epoll_del_connection(ngx_connection_t *c, u_int flags)
333 {
334 int op;
335 struct epoll_event ee;
336
337 /*
338 * when the file descriptor is closed the epoll automatically deletes
339 * it from its queue so we do not need to delete explicity the event
340 * before the closing the file descriptor
341 */
342
343 if (flags & NGX_CLOSE_EVENT) {
344 c->read->active = 0;
345 c->write->active = 0;
346 return NGX_OK;
347 }
348
349 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
350 "epoll del connection: fd:%d", c->fd);
351
352 op = EPOLL_CTL_DEL;
353 ee.events = 0;
354 ee.data.ptr = NULL;
355
356 if (epoll_ctl(ep, op, c->fd, &ee) == -1) {
357 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
358 "epoll_ctl(%d, %d) failed", op, c->fd);
359 return NGX_ERROR;
360 }
361
362 c->read->active = 0;
363 c->write->active = 0;
364
365 return NGX_OK;
366 }
367
368
369 int ngx_epoll_process_events(ngx_cycle_t *cycle)
370 {
371 int events;
372 size_t n;
373 ngx_int_t instance, i;
374 ngx_uint_t lock, accept_lock, expire;
375 ngx_err_t err;
376 ngx_log_t *log;
377 ngx_msec_t timer;
378 ngx_event_t *rev, *wev;
379 struct timeval tv;
380 ngx_connection_t *c;
381 ngx_epoch_msec_t delta;
382
383 for ( ;; ) {
384 timer = ngx_event_find_timer();
385
386 #if (NGX_THREADS)
387
388 if (timer == NGX_TIMER_ERROR) {
389 return NGX_ERROR;
390 }
391
392 if (timer == NGX_TIMER_INFINITE || timer > 500) {
393 timer = 500;
394 break;
395 }
396
397 #endif
398
399 if (timer != 0) {
400 break;
401 }
402
403 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
404 "epoll expired timer");
405
406 ngx_event_expire_timers((ngx_msec_t)
407 (ngx_elapsed_msec - ngx_old_elapsed_msec));
408
409 if (ngx_posted_events && ngx_threaded) {
410 ngx_wakeup_worker_thread(cycle);
411 }
412 }
413
414 /* NGX_TIMER_INFINITE == INFTIM */
415
416 if (timer == NGX_TIMER_INFINITE) {
417 expire = 0;
418
419 } else {
420 expire = 1;
421 }
422
423 ngx_old_elapsed_msec = ngx_elapsed_msec;
424 accept_lock = 0;
425
426 if (ngx_accept_mutex) {
427 if (ngx_accept_disabled > 0) {
428 ngx_accept_disabled--;
429
430 } else {
431 if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
432 return NGX_ERROR;
433 }
434
435 if (ngx_accept_mutex_held) {
436 accept_lock = 1;
437
438 } else if (timer == NGX_TIMER_INFINITE
439 || timer > ngx_accept_mutex_delay)
440 {
441 timer = ngx_accept_mutex_delay;
442 expire = 0;
443 }
444 }
445 }
446
447 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
448 "epoll timer: %d", timer);
449
450 events = epoll_wait(ep, event_list, nevents, timer);
451
452 if (events == -1) {
453 err = ngx_errno;
454 } else {
455 err = 0;
456 }
457
458 ngx_gettimeofday(&tv);
459 ngx_time_update(tv.tv_sec);
460
461 delta = ngx_elapsed_msec;
462 ngx_elapsed_msec = (ngx_epoch_msec_t) tv.tv_sec * 1000
463 + tv.tv_usec / 1000 - ngx_start_msec;
464
465 if (timer != NGX_TIMER_INFINITE) {
466 delta = ngx_elapsed_msec - delta;
467
468 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
469 "epoll timer: %d, delta: %d", timer, (int) delta);
470 } else {
471 if (events == 0) {
472 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
473 "epoll_wait() returned no events without timeout");
474 ngx_accept_mutex_unlock();
475 return NGX_ERROR;
476 }
477 }
478
479 if (err) {
480 ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT,
481 cycle->log, err, "epoll_wait() failed");
482 ngx_accept_mutex_unlock();
483 return NGX_ERROR;
484 }
485
486 if (events > 0) {
487 if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
488 ngx_accept_mutex_unlock();
489 return NGX_ERROR;
490 }
491
492 lock = 1;
493
494 } else {
495 lock =0;
496 }
497
498 log = cycle->log;
499
500 for (i = 0; i < events; i++) {
501 c = event_list[i].data.ptr;
502
503 instance = (uintptr_t) c & 1;
504 c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);
505
506 rev = c->read;
507
508 if (c->fd == -1 || rev->instance != instance) {
509
510 /*
511 * the stale event from a file descriptor
512 * that was just closed in this iteration
513 */
514
515 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
516 "epoll: stale event " PTR_FMT, c);
517 continue;
518 }
519
520 #if (NGX_DEBUG0)
521 log = c->log ? c->log : cycle->log;
522 #endif
523
524 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0,
525 "epoll: fd:%d ev:%04X d:" PTR_FMT,
526 c->fd, event_list[i].events, event_list[i].data);
527
528 if (event_list[i].events & (EPOLLERR|EPOLLHUP)) {
529 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0,
530 "epoll_wait() error on fd:%d ev:%04X",
531 c->fd, event_list[i].events);
532 }
533
534 if (event_list[i].events & ~(EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP)) {
535 ngx_log_error(NGX_LOG_ALERT, log, 0,
536 "strange epoll_wait() events fd:%d ev:%04X",
537 c->fd, event_list[i].events);
538 }
539
540 wev = c->write;
541
542 if ((event_list[i].events & (EPOLLOUT|EPOLLERR|EPOLLHUP))
543 && wev->active)
544 {
545 if (ngx_threaded) {
546 wev->posted_ready = 1;
547 ngx_post_event(wev);
548
549 } else {
550 wev->ready = 1;
551
552 if (!ngx_accept_mutex_held) {
553 wev->event_handler(wev);
554
555 } else {
556 ngx_post_event(wev);
557 }
558 }
559 }
560
561 /*
562 * EPOLLIN must be handled after EPOLLOUT because we use
563 * the optimization to avoid the unnecessary mutex locking/unlocking
564 * if the accept event is the last one.
565 */
566
567 if ((event_list[i].events & (EPOLLIN|EPOLLERR|EPOLLHUP))
568 && rev->active)
569 {
570 if (ngx_threaded && !rev->accept) {
571 rev->posted_ready = 1;
572
573 ngx_post_event(rev);
574
575 continue;
576 }
577
578 rev->ready = 1;
579
580 if (!ngx_threaded && !ngx_accept_mutex_held) {
581 rev->event_handler(rev);
582
583 } else if (!rev->accept) {
584 ngx_post_event(rev);
585
586 } else if (ngx_accept_disabled <= 0) {
587
588 ngx_mutex_unlock(ngx_posted_events_mutex);
589
590 rev->event_handler(rev);
591
592 if (ngx_accept_disabled > 0) {
593 ngx_accept_mutex_unlock();
594 accept_lock = 0;
595 }
596
597 if (i + 1 == events) {
598 lock = 0;
599 break;
600 }
601
602 if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
603 if (accept_lock) {
604 ngx_accept_mutex_unlock();
605 }
606 return NGX_ERROR;
607 }
608 }
609 }
610 }
611
612 if (accept_lock) {
613 ngx_accept_mutex_unlock();
614 }
615
616 if (lock) {
617 ngx_mutex_unlock(ngx_posted_events_mutex);
618 }
619
620 if (expire && delta) {
621 ngx_event_expire_timers((ngx_msec_t) delta);
622 }
623
624 if (ngx_posted_events) {
625 if (ngx_threaded) {
626 ngx_wakeup_worker_thread(cycle);
627
628 } else {
629 ngx_event_process_posted(cycle);
630 }
631 }
632
633 return NGX_OK;
634 }
635
636
637 static void *ngx_epoll_create_conf(ngx_cycle_t *cycle)
638 {
639 ngx_epoll_conf_t *epcf;
640
641 ngx_test_null(epcf, ngx_palloc(cycle->pool, sizeof(ngx_epoll_conf_t)),
642 NGX_CONF_ERROR);
643
644 epcf->events = NGX_CONF_UNSET;
645
646 return epcf;
647 }
648
649
650 static char *ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf)
651 {
652 ngx_epoll_conf_t *epcf = conf;
653
654 ngx_conf_init_unsigned_value(epcf->events, 512);
655
656 return NGX_CONF_OK;
657 }