Mercurial > hg > nginx-vendor-1-0
comparison src/event/modules/ngx_poll_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 | 46833bd150cb |
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 static ngx_int_t ngx_poll_init(ngx_cycle_t *cycle); | |
13 static void ngx_poll_done(ngx_cycle_t *cycle); | |
14 static ngx_int_t ngx_poll_add_event(ngx_event_t *ev, int event, u_int flags); | |
15 static ngx_int_t ngx_poll_del_event(ngx_event_t *ev, int event, u_int flags); | |
16 static ngx_int_t ngx_poll_process_events(ngx_cycle_t *cycle); | |
17 static char *ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf); | |
18 | |
19 | |
20 static struct pollfd *event_list; | |
21 static int nevents; | |
22 | |
23 #if 0 | |
24 static ngx_event_t **ready_index; | |
25 #endif | |
26 | |
27 static ngx_event_t *accept_events; | |
28 | |
29 | |
30 static ngx_str_t poll_name = ngx_string("poll"); | |
31 | |
32 ngx_event_module_t ngx_poll_module_ctx = { | |
33 &poll_name, | |
34 NULL, /* create configuration */ | |
35 ngx_poll_init_conf, /* init configuration */ | |
36 | |
37 { | |
38 ngx_poll_add_event, /* add an event */ | |
39 ngx_poll_del_event, /* delete an event */ | |
40 ngx_poll_add_event, /* enable an event */ | |
41 ngx_poll_del_event, /* disable an event */ | |
42 NULL, /* add an connection */ | |
43 NULL, /* delete an connection */ | |
44 NULL, /* process the changes */ | |
45 ngx_poll_process_events, /* process the events */ | |
46 ngx_poll_init, /* init the events */ | |
47 ngx_poll_done /* done the events */ | |
48 } | |
49 | |
50 }; | |
51 | |
52 ngx_module_t ngx_poll_module = { | |
53 NGX_MODULE, | |
54 &ngx_poll_module_ctx, /* module context */ | |
55 NULL, /* module directives */ | |
56 NGX_EVENT_MODULE, /* module type */ | |
57 NULL, /* init module */ | |
58 NULL /* init process */ | |
59 }; | |
60 | |
61 | |
62 | |
63 static ngx_int_t ngx_poll_init(ngx_cycle_t *cycle) | |
64 { | |
65 struct pollfd *list; | |
66 | |
67 if (event_list == NULL) { | |
68 nevents = 0; | |
69 } | |
70 | |
71 if (ngx_process == NGX_PROCESS_WORKER | |
72 || cycle->old_cycle == NULL | |
73 || cycle->old_cycle->connection_n < cycle->connection_n) | |
74 { | |
75 ngx_test_null(list, | |
76 ngx_alloc(sizeof(struct pollfd) * cycle->connection_n, | |
77 cycle->log), | |
78 NGX_ERROR); | |
79 | |
80 if (event_list) { | |
81 ngx_memcpy(list, event_list, sizeof(ngx_event_t *) * nevents); | |
82 ngx_free(event_list); | |
83 } | |
84 | |
85 event_list = list; | |
86 | |
87 #if 0 | |
88 if (ready_index) { | |
89 ngx_free(ready_index); | |
90 } | |
91 | |
92 ngx_test_null(ready_index, | |
93 ngx_alloc(sizeof(ngx_event_t *) * 2 * cycle->connection_n, | |
94 cycle->log), | |
95 NGX_ERROR); | |
96 #endif | |
97 } | |
98 | |
99 ngx_io = ngx_os_io; | |
100 | |
101 ngx_event_actions = ngx_poll_module_ctx.actions; | |
102 | |
103 ngx_event_flags = NGX_USE_LEVEL_EVENT|NGX_USE_ONESHOT_EVENT; | |
104 | |
105 return NGX_OK; | |
106 } | |
107 | |
108 | |
109 static void ngx_poll_done(ngx_cycle_t *cycle) | |
110 { | |
111 ngx_free(event_list); | |
112 #if 0 | |
113 ngx_free(ready_index); | |
114 #endif | |
115 | |
116 event_list = NULL; | |
117 #if 0 | |
118 ready_index = NULL; | |
119 #endif | |
120 } | |
121 | |
122 | |
123 static ngx_int_t ngx_poll_add_event(ngx_event_t *ev, int event, u_int flags) | |
124 { | |
125 ngx_event_t *e; | |
126 ngx_connection_t *c; | |
127 | |
128 c = ev->data; | |
129 | |
130 ev->active = 1; | |
131 | |
132 if (ev->index != NGX_INVALID_INDEX) { | |
133 ngx_log_error(NGX_LOG_ALERT, ev->log, 0, | |
134 "poll event fd:%d ev:%d is already set", c->fd, event); | |
135 return NGX_OK; | |
136 } | |
137 | |
138 if (event == NGX_READ_EVENT) { | |
139 e = c->write; | |
140 #if (NGX_READ_EVENT != POLLIN) | |
141 event = POLLIN; | |
142 #endif | |
143 | |
144 } else { | |
145 e = c->read; | |
146 #if (NGX_WRITE_EVENT != POLLOUT) | |
147 event = POLLOUT; | |
148 #endif | |
149 } | |
150 | |
151 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, | |
152 "poll add event: fd:%d ev:%d", c->fd, event); | |
153 | |
154 if (e == NULL || e->index == NGX_INVALID_INDEX) { | |
155 event_list[nevents].fd = c->fd; | |
156 event_list[nevents].events = event; | |
157 event_list[nevents].revents = 0; | |
158 | |
159 ev->index = nevents; | |
160 nevents++; | |
161 | |
162 } else { | |
163 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, | |
164 "poll add index: %d", e->index); | |
165 | |
166 event_list[e->index].events |= event; | |
167 ev->index = e->index; | |
168 } | |
169 | |
170 ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1 : 0; | |
171 | |
172 return NGX_OK; | |
173 } | |
174 | |
175 | |
176 static ngx_int_t ngx_poll_del_event(ngx_event_t *ev, int event, u_int flags) | |
177 { | |
178 ngx_uint_t i; | |
179 ngx_cycle_t **cycle; | |
180 ngx_event_t *e; | |
181 ngx_connection_t *c; | |
182 | |
183 c = ev->data; | |
184 | |
185 ev->active = 0; | |
186 | |
187 if (ev->index == NGX_INVALID_INDEX) { | |
188 ngx_log_error(NGX_LOG_ALERT, ev->log, 0, | |
189 "poll event fd:%d ev:%d is already deleted", | |
190 c->fd, event); | |
191 return NGX_OK; | |
192 } | |
193 | |
194 if (event == NGX_READ_EVENT) { | |
195 e = c->write; | |
196 #if (NGX_READ_EVENT != POLLIN) | |
197 event = POLLIN; | |
198 #endif | |
199 | |
200 } else { | |
201 e = c->read; | |
202 #if (NGX_WRITE_EVENT != POLLOUT) | |
203 event = POLLOUT; | |
204 #endif | |
205 } | |
206 | |
207 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, | |
208 "poll del event: fd:%d ev:%d", c->fd, event); | |
209 | |
210 if (e == NULL || e->index == NGX_INVALID_INDEX) { | |
211 nevents--; | |
212 | |
213 if (ev->index < (u_int) nevents) { | |
214 | |
215 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, | |
216 "index: copy event %d to %d", nevents, ev->index); | |
217 | |
218 event_list[ev->index] = event_list[nevents]; | |
219 | |
220 c = &ngx_cycle->connections[event_list[nevents].fd]; | |
221 | |
222 if (c->fd == -1) { | |
223 cycle = ngx_old_cycles.elts; | |
224 for (i = 0; i < ngx_old_cycles.nelts; i++) { | |
225 if (cycle[i] == NULL) { | |
226 continue; | |
227 } | |
228 c = &cycle[i]->connections[event_list[nevents].fd]; | |
229 if (c->fd != -1) { | |
230 break; | |
231 } | |
232 } | |
233 } | |
234 | |
235 if (c->fd == -1) { | |
236 ngx_log_error(NGX_LOG_ALERT, ev->log, 0, | |
237 "unexpected last event"); | |
238 | |
239 } else { | |
240 if (c->read->index == (u_int) nevents) { | |
241 c->read->index = ev->index; | |
242 } | |
243 | |
244 if (c->write->index == (u_int) nevents) { | |
245 c->write->index = ev->index; | |
246 } | |
247 } | |
248 } | |
249 | |
250 } else { | |
251 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, | |
252 "poll del index: %d", e->index); | |
253 | |
254 event_list[e->index].events &= ~event; | |
255 } | |
256 | |
257 ev->index = NGX_INVALID_INDEX; | |
258 | |
259 return NGX_OK; | |
260 } | |
261 | |
262 | |
263 static ngx_int_t ngx_poll_process_events(ngx_cycle_t *cycle) | |
264 { | |
265 int ready; | |
266 ngx_int_t i, nready; | |
267 ngx_uint_t n, found, lock, expire; | |
268 ngx_msec_t timer; | |
269 ngx_err_t err; | |
270 ngx_cycle_t **old_cycle; | |
271 ngx_event_t *ev; | |
272 ngx_epoch_msec_t delta; | |
273 ngx_connection_t *c; | |
274 struct timeval tv; | |
275 | |
276 for ( ;; ) { | |
277 timer = ngx_event_find_timer(); | |
278 | |
279 if (timer != 0) { | |
280 break; | |
281 } | |
282 | |
283 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
284 "poll expired timer"); | |
285 | |
286 ngx_event_expire_timers((ngx_msec_t) | |
287 (ngx_elapsed_msec - ngx_old_elapsed_msec)); | |
288 } | |
289 | |
290 /* NGX_TIMER_INFINITE == INFTIM */ | |
291 | |
292 if (timer == NGX_TIMER_INFINITE) { | |
293 expire = 0; | |
294 | |
295 } else { | |
296 expire = 1; | |
297 } | |
298 | |
299 ngx_old_elapsed_msec = ngx_elapsed_msec; | |
300 | |
301 #if (NGX_DEBUG0) | |
302 if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) { | |
303 for (i = 0; i < nevents; i++) { | |
304 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
305 "poll: %d: fd:%d ev:%04X", | |
306 i, event_list[i].fd, event_list[i].events); | |
307 } | |
308 } | |
309 #endif | |
310 | |
311 if (ngx_accept_mutex) { | |
312 if (ngx_accept_disabled > 0) { | |
313 ngx_accept_disabled--; | |
314 | |
315 } else { | |
316 if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) { | |
317 return NGX_ERROR; | |
318 } | |
319 | |
320 if (ngx_accept_mutex_held == 0 | |
321 && (timer == NGX_TIMER_INFINITE | |
322 || timer > ngx_accept_mutex_delay)) | |
323 { | |
324 timer = ngx_accept_mutex_delay; | |
325 expire = 0; | |
326 } | |
327 } | |
328 } | |
329 | |
330 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "poll timer: %d", timer); | |
331 | |
332 ready = poll(event_list, (u_int) nevents, (int) timer); | |
333 | |
334 if (ready == -1) { | |
335 err = ngx_errno; | |
336 } else { | |
337 err = 0; | |
338 } | |
339 | |
340 ngx_gettimeofday(&tv); | |
341 ngx_time_update(tv.tv_sec); | |
342 | |
343 delta = ngx_elapsed_msec; | |
344 ngx_elapsed_msec = (ngx_epoch_msec_t) tv.tv_sec * 1000 | |
345 + tv.tv_usec / 1000 - ngx_start_msec; | |
346 | |
347 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
348 "poll ready %d of %d", ready, nevents); | |
349 | |
350 if (err) { | |
351 ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT, | |
352 cycle->log, err, "poll() failed"); | |
353 ngx_accept_mutex_unlock(); | |
354 return NGX_ERROR; | |
355 } | |
356 | |
357 if (timer != NGX_TIMER_INFINITE) { | |
358 delta = ngx_elapsed_msec - delta; | |
359 | |
360 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
361 "poll timer: %d, delta: %d", timer, (int) delta); | |
362 } else { | |
363 if (ready == 0) { | |
364 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, | |
365 "poll() returned no events without timeout"); | |
366 ngx_accept_mutex_unlock(); | |
367 return NGX_ERROR; | |
368 } | |
369 } | |
370 | |
371 if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) { | |
372 ngx_accept_mutex_unlock(); | |
373 return NGX_ERROR; | |
374 } | |
375 | |
376 lock = 1; | |
377 nready = 0; | |
378 | |
379 for (i = 0; i < nevents && ready; i++) { | |
380 | |
381 #if 0 | |
382 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
383 "poll: %d: fd:%d ev:%04X rev:%04X", | |
384 i, event_list[i].fd, | |
385 event_list[i].events, event_list[i].revents); | |
386 #else | |
387 if (event_list[i].revents) { | |
388 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
389 "poll: %d: fd:%d ev:%04X rev:%04X", | |
390 i, event_list[i].fd, | |
391 event_list[i].events, event_list[i].revents); | |
392 } | |
393 #endif | |
394 | |
395 if (event_list[i].revents & POLLNVAL) { | |
396 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, | |
397 "poll() error fd:%d ev:%04X rev:%04X", | |
398 event_list[i].fd, | |
399 event_list[i].events, event_list[i].revents); | |
400 } | |
401 | |
402 if (event_list[i].revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) | |
403 { | |
404 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, | |
405 "strange poll() events fd:%d ev:%04X rev:%04X", | |
406 event_list[i].fd, | |
407 event_list[i].events, event_list[i].revents); | |
408 } | |
409 | |
410 if (event_list[i].fd == -1) { | |
411 /* | |
412 * the disabled event, a workaround for our possible bug, | |
413 * see the comment below | |
414 */ | |
415 continue; | |
416 } | |
417 | |
418 c = &ngx_cycle->connections[event_list[i].fd]; | |
419 | |
420 if (c->fd == -1) { | |
421 old_cycle = ngx_old_cycles.elts; | |
422 for (n = 0; n < ngx_old_cycles.nelts; n++) { | |
423 if (old_cycle[n] == NULL) { | |
424 continue; | |
425 } | |
426 c = &old_cycle[n]->connections[event_list[i].fd]; | |
427 if (c->fd != -1) { | |
428 break; | |
429 } | |
430 } | |
431 } | |
432 | |
433 if (c->fd == -1) { | |
434 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "unexpected event"); | |
435 | |
436 /* | |
437 * it is certainly our fault and it should be investigated, | |
438 * in the meantime we disable this event to avoid a CPU spinning | |
439 */ | |
440 | |
441 if (i == nevents - 1) { | |
442 nevents--; | |
443 } else { | |
444 event_list[i].fd = -1; | |
445 } | |
446 | |
447 continue; | |
448 } | |
449 | |
450 found = 0; | |
451 | |
452 if (event_list[i].revents & (POLLIN|POLLERR|POLLHUP|POLLNVAL)) { | |
453 found = 1; | |
454 | |
455 ev = c->read; | |
456 ev->ready = 1; | |
457 | |
458 if (ev->oneshot) { | |
459 if (ev->timer_set) { | |
460 ngx_del_timer(ev); | |
461 } | |
462 ngx_poll_del_event(ev, NGX_READ_EVENT, 0); | |
463 } | |
464 | |
465 if (ev->accept) { | |
466 ev->next = accept_events; | |
467 accept_events = ev; | |
468 } else { | |
469 ngx_post_event(ev); | |
470 } | |
471 | |
472 #if 0 | |
473 ready_index[nready++] = c->read; | |
474 #endif | |
475 } | |
476 | |
477 if (event_list[i].revents & (POLLOUT|POLLERR|POLLHUP|POLLNVAL)) { | |
478 found = 1; | |
479 ev = c->write; | |
480 ev->ready = 1; | |
481 | |
482 if (ev->oneshot) { | |
483 if (ev->timer_set) { | |
484 ngx_del_timer(ev); | |
485 } | |
486 ngx_poll_del_event(ev, NGX_WRITE_EVENT, 0); | |
487 } | |
488 | |
489 ngx_post_event(ev); | |
490 #if 0 | |
491 ready_index[nready++] = c->write; | |
492 #endif | |
493 } | |
494 | |
495 if (found) { | |
496 ready--; | |
497 continue; | |
498 } | |
499 } | |
500 | |
501 #if 0 | |
502 for (i = 0; i < nready; i++) { | |
503 ev = ready_index[i]; | |
504 | |
505 if (!ev->active) { | |
506 continue; | |
507 } | |
508 | |
509 ev->ready = 1; | |
510 | |
511 if (ev->oneshot) { | |
512 if (ev->timer_set) { | |
513 ngx_del_timer(ev); | |
514 } | |
515 | |
516 if (ev->write) { | |
517 ngx_poll_del_event(ev, NGX_WRITE_EVENT, 0); | |
518 } else { | |
519 ngx_poll_del_event(ev, NGX_READ_EVENT, 0); | |
520 } | |
521 } | |
522 | |
523 ev->event_handler(ev); | |
524 } | |
525 #endif | |
526 | |
527 ev = accept_events; | |
528 | |
529 for ( ;; ) { | |
530 | |
531 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
532 "accept event " PTR_FMT, ev); | |
533 | |
534 if (ev == NULL) { | |
535 break; | |
536 } | |
537 | |
538 ngx_mutex_unlock(ngx_posted_events_mutex); | |
539 | |
540 ev->event_handler(ev); | |
541 | |
542 if (ngx_accept_disabled > 0) { | |
543 lock = 0; | |
544 break; | |
545 } | |
546 | |
547 ev = ev->next; | |
548 | |
549 if (ev == NULL) { | |
550 lock = 0; | |
551 break; | |
552 } | |
553 | |
554 if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) { | |
555 ngx_accept_mutex_unlock(); | |
556 return NGX_ERROR; | |
557 } | |
558 | |
559 } | |
560 | |
561 ngx_accept_mutex_unlock(); | |
562 accept_events = NULL; | |
563 | |
564 if (lock) { | |
565 ngx_mutex_unlock(ngx_posted_events_mutex); | |
566 } | |
567 | |
568 if (ready != 0) { | |
569 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "poll ready != events"); | |
570 } | |
571 | |
572 if (expire && delta) { | |
573 ngx_event_expire_timers((ngx_msec_t) delta); | |
574 } | |
575 | |
576 if (!ngx_threaded) { | |
577 ngx_event_process_posted(cycle); | |
578 } | |
579 | |
580 return nready; | |
581 } | |
582 | |
583 | |
584 static char *ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf) | |
585 { | |
586 ngx_event_conf_t *ecf; | |
587 | |
588 ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); | |
589 | |
590 if (ecf->use != ngx_poll_module.ctx_index) { | |
591 return NGX_CONF_OK; | |
592 } | |
593 | |
594 #if (NGX_THREADS) | |
595 | |
596 ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, | |
597 "poll() is not supported in the threaded mode"); | |
598 return NGX_CONF_ERROR; | |
599 | |
600 #else | |
601 | |
602 return NGX_CONF_OK; | |
603 | |
604 #endif | |
605 } |