3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
12 #if (NGX_TEST_BUILD_RTSIG)
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
)
26 int ngx_linux_rtsig_max
;
33 ngx_int_t overflow_events
;
34 ngx_int_t overflow_test
;
35 ngx_int_t overflow_threshold
;
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
);
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
),
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
),
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
),
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
},
100 ngx_event_module_t ngx_rtsig_module_ctx
= {
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
= {
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 */
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
);
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");
149 ngx_free(overflow_list
);
152 overflow_list
= ngx_alloc(sizeof(struct pollfd
) * rtscf
->overflow_events
,
154 if (overflow_list
== NULL
) {
160 ngx_event_actions
= ngx_rtsig_module_ctx
.actions
;
162 ngx_event_flags
= NGX_USE_RTSIG_EVENT
|NGX_USE_GREEDY_EVENT
;
169 ngx_rtsig_done(ngx_cycle_t
*cycle
)
171 ngx_free(overflow_list
);
173 overflow_list
= NULL
;
178 ngx_rtsig_add_connection(ngx_connection_t
*c
)
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");
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");
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");
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");
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");
232 c
->write
->active
= 1;
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
);
250 c
->read
->disabled
= 1;
254 if (flags
& NGX_CLOSE_EVENT
) {
256 c
->write
->active
= 0;
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");
267 c
->write
->active
= 0;
274 ngx_rtsig_process_events(ngx_cycle_t
*cycle
)
282 ngx_event_t
*rev
, *wev
;
284 struct timespec ts
, *tp
;
286 ngx_epoch_msec_t delta
;
288 ngx_rtsig_conf_t
*rtscf
;
296 timer
= ngx_event_find_timer();
300 if (timer
== NGX_TIMER_ERROR
) {
304 if (timer
== NGX_TIMER_INFINITE
|| timer
> 500) {
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
);
328 if (ngx_accept_mutex
) {
329 if (ngx_accept_disabled
> 0) {
330 ngx_accept_disabled
--;
333 ngx_accept_mutex_held
= 0;
335 if (ngx_trylock_accept_mutex(cycle
) == 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
;
350 if (timer
== NGX_TIMER_INFINITE
) {
355 ts
.tv_sec
= timer
/ 1000;
356 ts
.tv_nsec
= (timer
% 1000) * 1000000;
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
);
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");
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
;
402 ngx_accept_mutex_unlock();
403 ngx_log_error((err
== NGX_EINTR
) ? NGX_LOG_INFO
: NGX_LOG_ALERT
,
404 cycle
->log
, err
, "sigtimedwait() failed");
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
) {
423 /* TODO: old_cycles */
425 c
= &ngx_cycle
->connections
[si
.si_fd
];
427 instance
= signo
- rtscf
->signo
;
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
);
446 if (si
.si_band
& (POLLIN
|POLLHUP
|POLLERR
)) {
449 if (ngx_threaded
&& !rev
->accept
) {
450 if (ngx_mutex_lock(ngx_posted_events_mutex
) == NGX_ERROR
) {
451 ngx_accept_mutex_unlock();
455 rev
->posted_ready
= 1;
458 ngx_mutex_unlock(ngx_posted_events_mutex
);
463 if (!ngx_threaded
&& !ngx_accept_mutex_held
) {
466 } else if (rev
->accept
) {
467 if (ngx_accept_disabled
<= 0) {
480 if (si
.si_band
& (POLLOUT
|POLLHUP
|POLLERR
)) {
484 if (ngx_mutex_lock(ngx_posted_events_mutex
) == NGX_ERROR
) {
485 ngx_accept_mutex_unlock();
489 wev
->posted_ready
= 1;
492 ngx_mutex_unlock(ngx_posted_events_mutex
);
497 if (!ngx_threaded
&& !ngx_accept_mutex_held
) {
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);
530 overflow_current
= 0;
531 ngx_event_actions
.process_events
= ngx_rtsig_process_overflow
;
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
);
544 ngx_accept_mutex_unlock();
546 if (expire
&& delta
) {
547 ngx_event_expire_timers((ngx_msec_t
) delta
);
550 if (ngx_posted_events
) {
552 ngx_wakeup_worker_thread(cycle
);
555 ngx_event_process_posted(cycle
);
567 /* TODO: old cylces */
570 ngx_rtsig_process_overflow(ngx_cycle_t
*cycle
)
572 int name
[2], rtsig_max
, rtsig_nr
, events
, ready
;
574 ngx_int_t tested
, n
, i
;
576 ngx_event_t
*rev
, *wev
;
578 ngx_rtsig_conf_t
*rtscf
;
580 rtscf
= ngx_event_get_conf(ngx_cycle
->conf_ctx
, ngx_rtsig_module
);
587 while (n
< rtscf
->overflow_events
) {
589 if (overflow_current
== cycle
->connection_n
) {
593 c
= &cycle
->connections
[overflow_current
++];
601 if (c
->read
->active
&& c
->read
->handler
) {
605 if (c
->write
->active
&& c
->write
->handler
) {
613 overflow_list
[n
].fd
= c
->fd
;
614 overflow_list
[n
].events
= events
;
615 overflow_list
[n
].revents
= 0;
624 ready
= poll(overflow_list
, n
, 0);
628 ngx_log_error((err
== NGX_EINTR
) ? NGX_LOG_INFO
: NGX_LOG_ALERT
,
630 "poll() failed while the overflow recover");
632 if (err
== NGX_EINTR
) {
644 if (ngx_mutex_lock(ngx_posted_events_mutex
) == NGX_ERROR
) {
648 for (i
= 0; i
< n
; i
++) {
649 c
= &cycle
->connections
[overflow_list
[i
].fd
];
656 && (overflow_list
[i
].revents
657 & (POLLIN
|POLLERR
|POLLHUP
|POLLNVAL
)))
662 rev
->posted_ready
= 1;
676 && (overflow_list
[i
].revents
677 & (POLLOUT
|POLLERR
|POLLHUP
|POLLNVAL
)))
682 wev
->posted_ready
= 1;
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
702 * Learn the /proc/sys/kernel/rtsig-max value because
703 * it can be changed since the last checking.
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");
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");
727 * drain the rt signal queue if the /proc/sys/kernel/rtsig-nr
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
) {
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 */ }
755 if (ngx_posted_events
) {
757 ngx_wakeup_worker_thread(cycle
);
760 ngx_event_process_posted(cycle
);
764 ngx_log_error(NGX_LOG_ALERT
, cycle
->log
, 0,
765 "rt signal queue overflow recovered");
768 ngx_event_actions
.process_events
= ngx_rtsig_process_events
;
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
));
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
;
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);
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");