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