Mercurial > hg > nginx-vendor-0-8
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 } |