nginx 0.1.38
[nginx-catap.git] / src / event / modules / ngx_rtsig_module.c
blob838b27d7036a9a6e7fedc165d3563da86f1b5c90
2 /*
3 * Copyright (C) Igor Sysoev
4 */
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_event.h>
12 #if (NGX_TEST_BUILD_RTSIG)
14 #define F_SETSIG 10
15 #define SIGRTMIN 33
16 #define si_fd __spare__[0]
17 #define KERN_RTSIGNR 30
18 #define KERN_RTSIGMAX 31
20 int sigtimedwait(const sigset_t *set, siginfo_t *info,
21 const struct timespec *timeout)
23 return -1;
26 int ngx_linux_rtsig_max;
28 #endif
31 typedef struct {
32 int signo;
33 ngx_int_t overflow_events;
34 ngx_int_t overflow_test;
35 ngx_int_t overflow_threshold;
36 } ngx_rtsig_conf_t;
39 extern ngx_event_module_t ngx_poll_module_ctx;
41 static ngx_int_t ngx_rtsig_init(ngx_cycle_t *cycle);
42 static void ngx_rtsig_done(ngx_cycle_t *cycle);
43 static ngx_int_t ngx_rtsig_add_connection(ngx_connection_t *c);
44 static ngx_int_t ngx_rtsig_del_connection(ngx_connection_t *c, u_int flags);
45 static ngx_int_t ngx_rtsig_process_events(ngx_cycle_t *cycle);
46 static ngx_int_t ngx_rtsig_process_overflow(ngx_cycle_t *cycle);
48 static void *ngx_rtsig_create_conf(ngx_cycle_t *cycle);
49 static char *ngx_rtsig_init_conf(ngx_cycle_t *cycle, void *conf);
50 static char *ngx_check_ngx_overflow_threshold_bounds(ngx_conf_t *cf,
51 void *post, void *data);
54 static sigset_t set;
55 static ngx_uint_t overflow, overflow_current;
56 static struct pollfd *overflow_list;
59 static ngx_str_t rtsig_name = ngx_string("rtsig");
61 static ngx_conf_num_bounds_t ngx_overflow_threshold_bounds = {
62 ngx_check_ngx_overflow_threshold_bounds, 2, 10
66 static ngx_command_t ngx_rtsig_commands[] = {
68 { ngx_string("rtsig_signo"),
69 NGX_EVENT_CONF|NGX_CONF_TAKE1,
70 ngx_conf_set_num_slot,
72 offsetof(ngx_rtsig_conf_t, signo),
73 NULL },
75 { ngx_string("rtsig_overflow_events"),
76 NGX_EVENT_CONF|NGX_CONF_TAKE1,
77 ngx_conf_set_num_slot,
79 offsetof(ngx_rtsig_conf_t, overflow_events),
80 NULL },
82 { ngx_string("rtsig_overflow_test"),
83 NGX_EVENT_CONF|NGX_CONF_TAKE1,
84 ngx_conf_set_num_slot,
86 offsetof(ngx_rtsig_conf_t, overflow_test),
87 NULL },
89 { ngx_string("rtsig_overflow_threshold"),
90 NGX_EVENT_CONF|NGX_CONF_TAKE1,
91 ngx_conf_set_num_slot,
93 offsetof(ngx_rtsig_conf_t, overflow_threshold),
94 &ngx_overflow_threshold_bounds },
96 ngx_null_command
100 ngx_event_module_t ngx_rtsig_module_ctx = {
101 &rtsig_name,
102 ngx_rtsig_create_conf, /* create configuration */
103 ngx_rtsig_init_conf, /* init configuration */
106 NULL, /* add an event */
107 NULL, /* delete an event */
108 NULL, /* enable an event */
109 NULL, /* disable an event */
110 ngx_rtsig_add_connection, /* add an connection */
111 ngx_rtsig_del_connection, /* delete an connection */
112 NULL, /* process the changes */
113 ngx_rtsig_process_events, /* process the events */
114 ngx_rtsig_init, /* init the events */
115 ngx_rtsig_done, /* done the events */
120 ngx_module_t ngx_rtsig_module = {
121 NGX_MODULE_V1,
122 &ngx_rtsig_module_ctx, /* module context */
123 ngx_rtsig_commands, /* module directives */
124 NGX_EVENT_MODULE, /* module type */
125 NULL, /* init module */
126 NULL /* init process */
130 static ngx_int_t
131 ngx_rtsig_init(ngx_cycle_t *cycle)
133 ngx_rtsig_conf_t *rtscf;
135 rtscf = ngx_event_get_conf(cycle->conf_ctx, ngx_rtsig_module);
137 sigemptyset(&set);
138 sigaddset(&set, rtscf->signo);
139 sigaddset(&set, rtscf->signo + 1);
140 sigaddset(&set, SIGIO);
142 if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) {
143 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
144 "sigprocmask() failed");
145 return NGX_ERROR;
148 if (overflow_list) {
149 ngx_free(overflow_list);
152 overflow_list = ngx_alloc(sizeof(struct pollfd) * rtscf->overflow_events,
153 cycle->log);
154 if (overflow_list == NULL) {
155 return NGX_ERROR;
158 ngx_io = ngx_os_io;
160 ngx_event_actions = ngx_rtsig_module_ctx.actions;
162 ngx_event_flags = NGX_USE_RTSIG_EVENT|NGX_USE_GREEDY_EVENT;
164 return NGX_OK;
168 static void
169 ngx_rtsig_done(ngx_cycle_t *cycle)
171 ngx_free(overflow_list);
173 overflow_list = NULL;
177 static ngx_int_t
178 ngx_rtsig_add_connection(ngx_connection_t *c)
180 int signo;
181 ngx_rtsig_conf_t *rtscf;
183 if (c->read->accept && c->read->disabled) {
185 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
186 "rtsig enable connection: fd:%d", c->fd);
188 if (fcntl(c->fd, F_SETOWN, ngx_pid) == -1) {
189 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
190 "fcntl(F_SETOWN) failed");
191 return NGX_ERROR;
194 c->read->active = 1;
195 c->read->disabled = 0;
198 rtscf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_rtsig_module);
200 signo = rtscf->signo + c->read->instance;
202 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
203 "rtsig add connection: fd:%d signo:%d", c->fd, signo);
205 if (fcntl(c->fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC) == -1) {
206 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
207 "fcntl(O_RDWR|O_NONBLOCK|O_ASYNC) failed");
208 return NGX_ERROR;
211 if (fcntl(c->fd, F_SETSIG, signo) == -1) {
212 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
213 "fcntl(F_SETSIG) failed");
214 return NGX_ERROR;
217 if (fcntl(c->fd, F_SETOWN, ngx_pid) == -1) {
218 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
219 "fcntl(F_SETOWN) failed");
220 return NGX_ERROR;
223 #if (NGX_HAVE_ONESIGFD)
224 if (fcntl(c->fd, F_SETAUXFL, O_ONESIGFD) == -1) {
225 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
226 "fcntl(F_SETAUXFL) failed");
227 return NGX_ERROR;
229 #endif
231 c->read->active = 1;
232 c->write->active = 1;
234 return NGX_OK;
238 static ngx_int_t
239 ngx_rtsig_del_connection(ngx_connection_t *c, u_int flags)
241 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
242 "rtsig del connection: fd:%d", c->fd);
244 if ((flags & NGX_DISABLE_EVENT) && c->read->accept) {
246 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
247 "rtsig disable connection: fd:%d", c->fd);
249 c->read->active = 0;
250 c->read->disabled = 1;
251 return NGX_OK;
254 if (flags & NGX_CLOSE_EVENT) {
255 c->read->active = 0;
256 c->write->active = 0;
257 return NGX_OK;
260 if (fcntl(c->fd, F_SETFL, O_RDWR|O_NONBLOCK) == -1) {
261 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
262 "fcntl(O_RDWR|O_NONBLOCK) failed");
263 return NGX_ERROR;
266 c->read->active = 0;
267 c->write->active = 0;
269 return NGX_OK;
273 static ngx_int_t
274 ngx_rtsig_process_events(ngx_cycle_t *cycle)
276 int signo;
277 ngx_int_t instance;
278 ngx_uint_t expire;
279 ngx_msec_t timer;
280 ngx_err_t err;
281 siginfo_t si;
282 ngx_event_t *rev, *wev;
283 struct timeval tv;
284 struct timespec ts, *tp;
285 struct sigaction sa;
286 ngx_epoch_msec_t delta;
287 ngx_connection_t *c;
288 ngx_rtsig_conf_t *rtscf;
290 if (overflow) {
291 timer = 0;
292 expire = 0;
294 } else {
295 for ( ;; ) {
296 timer = ngx_event_find_timer();
298 #if (NGX_THREADS)
300 if (timer == NGX_TIMER_ERROR) {
301 return NGX_ERROR;
304 if (timer == NGX_TIMER_INFINITE || timer > 500) {
305 timer = 500;
306 break;
309 #endif
311 if (timer != 0) {
312 break;
315 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
316 "rtsig expired timer");
318 ngx_event_expire_timers((ngx_msec_t)
319 (ngx_elapsed_msec - ngx_old_elapsed_msec));
321 if (ngx_posted_events && ngx_threaded) {
322 ngx_wakeup_worker_thread(cycle);
326 expire = 1;
328 if (ngx_accept_mutex) {
329 if (ngx_accept_disabled > 0) {
330 ngx_accept_disabled--;
332 } else {
333 ngx_accept_mutex_held = 0;
335 if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
336 return NGX_ERROR;
339 if (ngx_accept_mutex_held == 0
340 && (timer == NGX_TIMER_INFINITE
341 || timer > ngx_accept_mutex_delay))
343 timer = ngx_accept_mutex_delay;
344 expire = 0;
350 if (timer == NGX_TIMER_INFINITE) {
351 tp = NULL;
352 expire = 0;
354 } else {
355 ts.tv_sec = timer / 1000;
356 ts.tv_nsec = (timer % 1000) * 1000000;
357 tp = &ts;
360 ngx_old_elapsed_msec = ngx_elapsed_msec;
362 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
363 "rtsig timer: %d", timer);
365 /* Linux's sigwaitinfo() is sigtimedwait() with the NULL timeout pointer */
367 signo = sigtimedwait(&set, &si, tp);
369 if (signo == -1) {
370 err = ngx_errno;
372 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, err,
373 "rtsig signo:%d", signo);
375 if (err == NGX_EAGAIN) {
377 if (timer == NGX_TIMER_INFINITE) {
378 ngx_accept_mutex_unlock();
379 ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
380 "sigtimedwait() returned EAGAIN without timeout");
381 return NGX_ERROR;
384 err = 0;
387 } else {
388 err = 0;
389 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
390 "rtsig signo:%d fd:%d band:%04Xd",
391 signo, si.si_fd, si.si_band);
394 ngx_gettimeofday(&tv);
395 ngx_time_update(tv.tv_sec);
397 delta = ngx_elapsed_msec;
398 ngx_elapsed_msec = (ngx_epoch_msec_t) tv.tv_sec * 1000
399 + tv.tv_usec / 1000 - ngx_start_msec;
401 if (err) {
402 ngx_accept_mutex_unlock();
403 ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT,
404 cycle->log, err, "sigtimedwait() failed");
405 return NGX_ERROR;
408 if (timer != NGX_TIMER_INFINITE) {
409 delta = ngx_elapsed_msec - delta;
411 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
412 "rtsig timer: %d, delta: %d", timer, (int) delta);
415 rtscf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_rtsig_module);
417 if (signo == rtscf->signo || signo == rtscf->signo + 1) {
419 if (overflow && (ngx_uint_t) si.si_fd > overflow_current) {
420 return NGX_OK;
423 /* TODO: old_cycles */
425 c = &ngx_cycle->connections[si.si_fd];
427 instance = signo - rtscf->signo;
429 rev = c->read;
431 if (c->read->instance != instance) {
434 * the stale event from a file descriptor
435 * that was just closed in this iteration
438 ngx_accept_mutex_unlock();
440 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
441 "rtsig: stale event %p", c);
443 return NGX_OK;
446 if (si.si_band & (POLLIN|POLLHUP|POLLERR)) {
447 if (rev->active) {
449 if (ngx_threaded && !rev->accept) {
450 if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
451 ngx_accept_mutex_unlock();
452 return NGX_ERROR;
455 rev->posted_ready = 1;
456 ngx_post_event(rev);
458 ngx_mutex_unlock(ngx_posted_events_mutex);
460 } else {
461 rev->ready = 1;
463 if (!ngx_threaded && !ngx_accept_mutex_held) {
464 rev->handler(rev);
466 } else if (rev->accept) {
467 if (ngx_accept_disabled <= 0) {
468 rev->handler(rev);
471 } else {
472 ngx_post_event(rev);
478 wev = c->write;
480 if (si.si_band & (POLLOUT|POLLHUP|POLLERR)) {
481 if (wev->active) {
483 if (ngx_threaded) {
484 if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
485 ngx_accept_mutex_unlock();
486 return NGX_ERROR;
489 wev->posted_ready = 1;
490 ngx_post_event(wev);
492 ngx_mutex_unlock(ngx_posted_events_mutex);
494 } else {
495 wev->ready = 1;
497 if (!ngx_threaded && !ngx_accept_mutex_held) {
498 wev->handler(wev);
500 } else {
501 ngx_post_event(wev);
507 } else if (signo == SIGIO) {
508 ngx_accept_mutex_unlock();
510 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
511 "rt signal queue overflowed");
513 /* flush the RT signal queue */
515 ngx_memzero(&sa, sizeof(struct sigaction));
516 sa.sa_handler = SIG_DFL;
517 sigemptyset(&sa.sa_mask);
519 if (sigaction(rtscf->signo, &sa, NULL) == -1) {
520 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
521 "sigaction(%d, SIG_DFL) failed", rtscf->signo);
524 if (sigaction(rtscf->signo + 1, &sa, NULL) == -1) {
525 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
526 "sigaction(%d, SIG_DFL) failed", rtscf->signo + 1);
529 overflow = 1;
530 overflow_current = 0;
531 ngx_event_actions.process_events = ngx_rtsig_process_overflow;
533 return NGX_ERROR;
535 } else if (signo != -1) {
536 ngx_accept_mutex_unlock();
538 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
539 "sigtimedwait() returned unexpected signal: %d", signo);
541 return NGX_ERROR;
544 ngx_accept_mutex_unlock();
546 if (expire && delta) {
547 ngx_event_expire_timers((ngx_msec_t) delta);
550 if (ngx_posted_events) {
551 if (ngx_threaded) {
552 ngx_wakeup_worker_thread(cycle);
554 } else {
555 ngx_event_process_posted(cycle);
559 if (signo == -1) {
560 return NGX_AGAIN;
561 } else {
562 return NGX_OK;
567 /* TODO: old cylces */
569 static ngx_int_t
570 ngx_rtsig_process_overflow(ngx_cycle_t *cycle)
572 int name[2], rtsig_max, rtsig_nr, events, ready;
573 size_t len;
574 ngx_int_t tested, n, i;
575 ngx_err_t err;
576 ngx_event_t *rev, *wev;
577 ngx_connection_t *c;
578 ngx_rtsig_conf_t *rtscf;
580 rtscf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_rtsig_module);
582 tested = 0;
584 for ( ;; ) {
586 n = 0;
587 while (n < rtscf->overflow_events) {
589 if (overflow_current == cycle->connection_n) {
590 break;
593 c = &cycle->connections[overflow_current++];
595 if (c->fd == -1) {
596 continue;
599 events = 0;
601 if (c->read->active && c->read->handler) {
602 events |= POLLIN;
605 if (c->write->active && c->write->handler) {
606 events |= POLLOUT;
609 if (events == 0) {
610 continue;
613 overflow_list[n].fd = c->fd;
614 overflow_list[n].events = events;
615 overflow_list[n].revents = 0;
616 n++;
619 if (n == 0) {
620 break;
623 for ( ;; ) {
624 ready = poll(overflow_list, n, 0);
626 if (ready == -1) {
627 err = ngx_errno;
628 ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT,
629 cycle->log, 0,
630 "poll() failed while the overflow recover");
632 if (err == NGX_EINTR) {
633 continue;
637 break;
640 if (ready <= 0) {
641 continue;
644 if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
645 return NGX_ERROR;
648 for (i = 0; i < n; i++) {
649 c = &cycle->connections[overflow_list[i].fd];
651 rev = c->read;
653 if (rev->active
654 && !rev->closed
655 && rev->handler
656 && (overflow_list[i].revents
657 & (POLLIN|POLLERR|POLLHUP|POLLNVAL)))
659 tested++;
661 if (ngx_threaded) {
662 rev->posted_ready = 1;
663 ngx_post_event(rev);
665 } else {
666 rev->ready = 1;
667 rev->handler(rev);
671 wev = c->write;
673 if (wev->active
674 && !wev->closed
675 && wev->handler
676 && (overflow_list[i].revents
677 & (POLLOUT|POLLERR|POLLHUP|POLLNVAL)))
679 tested++;
681 if (ngx_threaded) {
682 wev->posted_ready = 1;
683 ngx_post_event(wev);
685 } else {
686 wev->ready = 1;
687 wev->handler(wev);
692 ngx_mutex_unlock(ngx_posted_events_mutex);
694 if (tested >= rtscf->overflow_test) {
696 if (ngx_linux_rtsig_max) {
699 * Check the current rt queue length to prevent
700 * the new overflow.
702 * Learn the /proc/sys/kernel/rtsig-max value because
703 * it can be changed since the last checking.
706 name[0] = CTL_KERN;
707 name[1] = KERN_RTSIGMAX;
708 len = sizeof(rtsig_max);
710 if (sysctl(name, 2, &rtsig_max, &len, NULL, 0) == -1) {
711 ngx_log_error(NGX_LOG_ALERT, cycle->log, errno,
712 "sysctl(KERN_RTSIGMAX) failed");
713 return NGX_ERROR;
716 /* name[0] = CTL_KERN; */
717 name[1] = KERN_RTSIGNR;
718 len = sizeof(rtsig_nr);
720 if (sysctl(name, 2, &rtsig_nr, &len, NULL, 0) == -1) {
721 ngx_log_error(NGX_LOG_ALERT, cycle->log, errno,
722 "sysctl(KERN_RTSIGNR) failed");
723 return NGX_ERROR;
727 * drain the rt signal queue if the /proc/sys/kernel/rtsig-nr
728 * is bigger than
729 * /proc/sys/kernel/rtsig-max / rtsig_overflow_threshold
732 if (rtsig_max / rtscf->overflow_threshold < rtsig_nr) {
733 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
734 "rtsig queue state: %d/%d",
735 rtsig_nr, rtsig_max);
736 while (ngx_rtsig_process_events(cycle) == NGX_OK) {
737 /* void */
741 } else {
744 * Linux has not KERN_RTSIGMAX since 2.6.6-mm2
745 * so drain the rt signal queue unconditionally
748 while (ngx_rtsig_process_events(cycle) == NGX_OK) { /* void */ }
751 tested = 0;
755 if (ngx_posted_events) {
756 if (ngx_threaded) {
757 ngx_wakeup_worker_thread(cycle);
759 } else {
760 ngx_event_process_posted(cycle);
764 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
765 "rt signal queue overflow recovered");
767 overflow = 0;
768 ngx_event_actions.process_events = ngx_rtsig_process_events;
770 return NGX_OK;
774 static void *
775 ngx_rtsig_create_conf(ngx_cycle_t *cycle)
777 ngx_rtsig_conf_t *rtscf;
779 rtscf = ngx_palloc(cycle->pool, sizeof(ngx_rtsig_conf_t));
780 if (rtscf == NULL) {
781 return NGX_CONF_ERROR;
784 rtscf->signo = NGX_CONF_UNSET;
785 rtscf->overflow_events = NGX_CONF_UNSET;
786 rtscf->overflow_test = NGX_CONF_UNSET;
787 rtscf->overflow_threshold = NGX_CONF_UNSET;
789 return rtscf;
793 static char *
794 ngx_rtsig_init_conf(ngx_cycle_t *cycle, void *conf)
796 ngx_rtsig_conf_t *rtscf = conf;
798 /* LinuxThreads use the first 3 RT signals */
799 ngx_conf_init_value(rtscf->signo, SIGRTMIN + 10);
801 ngx_conf_init_value(rtscf->overflow_events, 16);
802 ngx_conf_init_value(rtscf->overflow_test, 32);
803 ngx_conf_init_value(rtscf->overflow_threshold, 10);
805 return NGX_CONF_OK;
809 static char *
810 ngx_check_ngx_overflow_threshold_bounds(ngx_conf_t *cf,
811 void *post, void *data)
813 if (ngx_linux_rtsig_max) {
814 return ngx_conf_check_num_bounds(cf, post, data);
817 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
818 "\"rtsig_overflow_threshold\" is not supported "
819 "since Linux 2.6.6-mm2, ignored");
821 return NGX_CONF_OK;