upstream nginx-0.7.35
[nginx.git] / nginx / src / event / modules / ngx_rtsig_module.c
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 (NGX_TEST_BUILD_RTSIG)
13
14 #ifdef  SIGRTMIN
15 #define si_fd          _reason.__spare__.__spare2__[0]
16 #else
17 #define SIGRTMIN       33
18 #define si_fd          __spare__[0]
19 #endif
20
21 #define F_SETSIG       10
22 #define KERN_RTSIGNR   30
23 #define KERN_RTSIGMAX  31
24
25 int sigtimedwait(const sigset_t *set, siginfo_t *info,
26                  const struct timespec *timeout)
27 {
28     return -1;
29 }
30
31 int ngx_linux_rtsig_max;
32
33 #endif
34
35
36 typedef struct {
37     ngx_uint_t  signo;
38     ngx_uint_t  overflow_events;
39     ngx_uint_t  overflow_test;
40     ngx_uint_t  overflow_threshold;
41 } ngx_rtsig_conf_t;
42
43
44 extern ngx_event_module_t  ngx_poll_module_ctx;
45
46 static ngx_int_t ngx_rtsig_init(ngx_cycle_t *cycle, ngx_msec_t timer);
47 static void ngx_rtsig_done(ngx_cycle_t *cycle);
48 static ngx_int_t ngx_rtsig_add_connection(ngx_connection_t *c);
49 static ngx_int_t ngx_rtsig_del_connection(ngx_connection_t *c,
50     ngx_uint_t flags);
51 static ngx_int_t ngx_rtsig_process_events(ngx_cycle_t *cycle,
52     ngx_msec_t timer, ngx_uint_t flags);
53 static ngx_int_t ngx_rtsig_process_overflow(ngx_cycle_t *cycle,
54     ngx_msec_t timer, ngx_uint_t flags);
55
56 static void *ngx_rtsig_create_conf(ngx_cycle_t *cycle);
57 static char *ngx_rtsig_init_conf(ngx_cycle_t *cycle, void *conf);
58 static char *ngx_check_ngx_overflow_threshold_bounds(ngx_conf_t *cf,
59     void *post, void *data);
60
61
62 static sigset_t        set;
63 static ngx_uint_t      overflow, overflow_current;
64 static struct pollfd  *overflow_list;
65
66
67 static ngx_str_t      rtsig_name = ngx_string("rtsig");
68
69 static ngx_conf_num_bounds_t  ngx_overflow_threshold_bounds = {
70     ngx_check_ngx_overflow_threshold_bounds, 2, 10
71 };
72
73
74 static ngx_command_t  ngx_rtsig_commands[] = {
75
76     { ngx_string("rtsig_signo"),
77       NGX_EVENT_CONF|NGX_CONF_TAKE1,
78       ngx_conf_set_num_slot,
79       0,
80       offsetof(ngx_rtsig_conf_t, signo),
81       NULL },
82
83     { ngx_string("rtsig_overflow_events"),
84       NGX_EVENT_CONF|NGX_CONF_TAKE1,
85       ngx_conf_set_num_slot,
86       0,
87       offsetof(ngx_rtsig_conf_t, overflow_events),
88       NULL },
89
90     { ngx_string("rtsig_overflow_test"),
91       NGX_EVENT_CONF|NGX_CONF_TAKE1,
92       ngx_conf_set_num_slot,
93       0,
94       offsetof(ngx_rtsig_conf_t, overflow_test),
95       NULL },
96
97     { ngx_string("rtsig_overflow_threshold"),
98       NGX_EVENT_CONF|NGX_CONF_TAKE1,
99       ngx_conf_set_num_slot,
100       0,
101       offsetof(ngx_rtsig_conf_t, overflow_threshold),
102       &ngx_overflow_threshold_bounds },
103
104       ngx_null_command
105 };
106
107
108 ngx_event_module_t  ngx_rtsig_module_ctx = {
109     &rtsig_name,
110     ngx_rtsig_create_conf,               /* create configuration */
111     ngx_rtsig_init_conf,                 /* init configuration */
112
113     {
114         NULL,                            /* add an event */
115         NULL,                            /* delete an event */
116         NULL,                            /* enable an event */
117         NULL,                            /* disable an event */
118         ngx_rtsig_add_connection,        /* add an connection */
119         ngx_rtsig_del_connection,        /* delete an connection */
120         NULL,                            /* process the changes */
121         ngx_rtsig_process_events,        /* process the events */
122         ngx_rtsig_init,                  /* init the events */
123         ngx_rtsig_done,                  /* done the events */
124     }
125
126 };
127
128 ngx_module_t  ngx_rtsig_module = {
129     NGX_MODULE_V1,
130     &ngx_rtsig_module_ctx,               /* module context */
131     ngx_rtsig_commands,                  /* module directives */
132     NGX_EVENT_MODULE,                    /* module type */
133     NULL,                                /* init master */
134     NULL,                                /* init module */
135     NULL,                                /* init process */
136     NULL,                                /* init thread */
137     NULL,                                /* exit thread */
138     NULL,                                /* exit process */
139     NULL,                                /* exit master */
140     NGX_MODULE_V1_PADDING
141 };
142
143
144 static ngx_int_t
145 ngx_rtsig_init(ngx_cycle_t *cycle, ngx_msec_t timer)
146 {
147     ngx_rtsig_conf_t  *rtscf;
148
149     rtscf = ngx_event_get_conf(cycle->conf_ctx, ngx_rtsig_module);
150
151     sigemptyset(&set);
152     sigaddset(&set, (int) rtscf->signo);
153     sigaddset(&set, (int) rtscf->signo + 1);
154     sigaddset(&set, SIGIO);
155     sigaddset(&set, SIGALRM);
156
157     if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) {
158         ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
159                       "sigprocmask() failed");
160         return NGX_ERROR;
161     }
162
163     if (overflow_list) {
164         ngx_free(overflow_list);
165     }
166
167     overflow_list = ngx_alloc(sizeof(struct pollfd) * rtscf->overflow_events,
168                               cycle->log);
169     if (overflow_list == NULL) {
170         return NGX_ERROR;
171     }
172
173     ngx_io = ngx_os_io;
174
175     ngx_event_actions = ngx_rtsig_module_ctx.actions;
176
177     ngx_event_flags = NGX_USE_RTSIG_EVENT
178                       |NGX_USE_GREEDY_EVENT
179                       |NGX_USE_FD_EVENT;
180
181     return NGX_OK;
182 }
183
184
185 static void
186 ngx_rtsig_done(ngx_cycle_t *cycle)
187 {
188     ngx_free(overflow_list);
189
190     overflow_list = NULL;
191 }
192
193
194 static ngx_int_t
195 ngx_rtsig_add_connection(ngx_connection_t *c)
196 {
197     ngx_uint_t         signo;
198     ngx_rtsig_conf_t  *rtscf;
199
200     if (c->read->accept && c->read->disabled) {
201
202         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
203                        "rtsig enable connection: fd:%d", c->fd);
204
205         if (fcntl(c->fd, F_SETOWN, ngx_pid) == -1) {
206             ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
207                           "fcntl(F_SETOWN) failed");
208             return NGX_ERROR;
209         }
210
211         c->read->active = 1;
212         c->read->disabled = 0;
213     }
214
215     rtscf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_rtsig_module);
216
217     signo = rtscf->signo + c->read->instance;
218
219     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
220                    "rtsig add connection: fd:%d signo:%ui", c->fd, signo);
221
222     if (fcntl(c->fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC) == -1) {
223         ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
224                       "fcntl(O_RDWR|O_NONBLOCK|O_ASYNC) failed");
225         return NGX_ERROR;
226     }
227
228     if (fcntl(c->fd, F_SETSIG, (int) signo) == -1) {
229         ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
230                       "fcntl(F_SETSIG) failed");
231         return NGX_ERROR;
232     }
233
234     if (fcntl(c->fd, F_SETOWN, ngx_pid) == -1) {
235         ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
236                       "fcntl(F_SETOWN) failed");
237         return NGX_ERROR;
238     }
239
240 #if (NGX_HAVE_ONESIGFD)
241     if (fcntl(c->fd, F_SETAUXFL, O_ONESIGFD) == -1) {
242         ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
243                       "fcntl(F_SETAUXFL) failed");
244         return NGX_ERROR;
245     }
246 #endif
247
248     c->read->active = 1;
249     c->write->active = 1;
250
251     return NGX_OK;
252 }
253
254
255 static ngx_int_t
256 ngx_rtsig_del_connection(ngx_connection_t *c, ngx_uint_t flags)
257 {
258     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
259                    "rtsig del connection: fd:%d", c->fd);
260
261     if ((flags & NGX_DISABLE_EVENT) && c->read->accept) {
262
263         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
264                        "rtsig disable connection: fd:%d", c->fd);
265
266         c->read->active = 0;
267         c->read->disabled = 1;
268         return NGX_OK;
269     }
270
271     if (flags & NGX_CLOSE_EVENT) {
272         c->read->active = 0;
273         c->write->active = 0;
274         return NGX_OK;
275     }
276
277     if (fcntl(c->fd, F_SETFL, O_RDWR|O_NONBLOCK) == -1) {
278         ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
279                       "fcntl(O_RDWR|O_NONBLOCK) failed");
280         return NGX_ERROR;
281     }
282
283     c->read->active = 0;
284     c->write->active = 0;
285
286     return NGX_OK;
287 }
288
289
290 static ngx_int_t
291 ngx_rtsig_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
292 {
293     int                 signo;
294     ngx_int_t           instance;
295     ngx_err_t           err;
296     siginfo_t           si;
297     ngx_event_t        *rev, *wev, **queue;
298     struct timespec     ts, *tp;
299     struct sigaction    sa;
300     ngx_connection_t   *c;
301     ngx_rtsig_conf_t   *rtscf;
302
303     if (timer == NGX_TIMER_INFINITE) {
304         tp = NULL;
305
306     } else {
307         ts.tv_sec = timer / 1000;
308         ts.tv_nsec = (timer % 1000) * 1000000;
309         tp = &ts;
310     }
311
312     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
313                    "rtsig timer: %M", timer);
314
315     /* Linux's sigwaitinfo() is sigtimedwait() with the NULL timeout pointer */
316
317     signo = sigtimedwait(&set, &si, tp);
318
319     if (signo == -1) {
320         err = ngx_errno;
321
322         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, err,
323                        "rtsig signo:%d", signo);
324
325         if (flags & NGX_UPDATE_TIME) {
326             ngx_time_update(0, 0);
327         }
328
329         if (err == NGX_EAGAIN) {
330
331             /* timeout */
332
333             if (timer != NGX_TIMER_INFINITE) {
334                 return NGX_AGAIN;
335             }
336
337             ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
338                           "sigtimedwait() returned EAGAIN without timeout");
339             return NGX_ERROR;
340         }
341
342         ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT,
343                       cycle->log, err, "sigtimedwait() failed");
344         return NGX_ERROR;
345     }
346
347     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
348                    "rtsig signo:%d fd:%d band:%04Xd",
349                    signo, si.si_fd, si.si_band);
350
351     if (flags & NGX_UPDATE_TIME) {
352         ngx_time_update(0, 0);
353     }
354
355     rtscf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_rtsig_module);
356
357     if (signo == (int) rtscf->signo || signo == (int) rtscf->signo + 1) {
358
359         if (overflow && (ngx_uint_t) si.si_fd > overflow_current) {
360             return NGX_OK;
361         }
362
363         c = ngx_cycle->files[si.si_fd];
364
365         if (c == NULL) {
366
367             /* the stale event */
368
369             return NGX_OK;
370         }
371
372         instance = signo - (int) rtscf->signo;
373
374         rev = c->read;
375
376         if (rev->instance != instance) {
377
378             /*
379              * the stale event from a file descriptor
380              * that was just closed in this iteration
381              */
382
383             ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
384                            "rtsig: stale event %p", c);
385
386             return NGX_OK;
387         }
388
389         if ((si.si_band & (POLLIN|POLLHUP|POLLERR)) && rev->active) {
390
391             rev->ready = 1;
392
393             if (flags & NGX_POST_EVENTS) {
394                 queue = (ngx_event_t **) (rev->accept ?
395                                &ngx_posted_accept_events : &ngx_posted_events);
396
397                 ngx_locked_post_event(rev, queue);
398
399             } else {
400                 rev->handler(rev);
401             }
402         }
403
404         wev = c->write;
405
406         if ((si.si_band & (POLLOUT|POLLHUP|POLLERR)) && wev->active) {
407
408             wev->ready = 1;
409
410             if (flags & NGX_POST_EVENTS) {
411                 ngx_locked_post_event(wev, &ngx_posted_events);
412
413             } else {
414                 wev->handler(wev);
415             }
416         }
417
418         return NGX_OK;
419
420     } else if (signo == SIGALRM) {
421
422         ngx_time_update(0, 0);
423
424         return NGX_OK;
425
426     } else if (signo == SIGIO) {
427
428         ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
429                       "rt signal queue overflowed");
430
431         /* flush the RT signal queue */
432
433         ngx_memzero(&sa, sizeof(struct sigaction));
434         sa.sa_handler = SIG_DFL;
435         sigemptyset(&sa.sa_mask);
436
437         if (sigaction(rtscf->signo, &sa, NULL) == -1) {
438             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
439                           "sigaction(%d, SIG_DFL) failed", rtscf->signo);
440         }
441
442         if (sigaction(rtscf->signo + 1, &sa, NULL) == -1) {
443             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
444                           "sigaction(%d, SIG_DFL) failed", rtscf->signo + 1);
445         }
446
447         overflow = 1;
448         overflow_current = 0;
449         ngx_event_actions.process_events = ngx_rtsig_process_overflow;
450
451         return NGX_ERROR;
452
453     }
454
455     ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
456                   "sigtimedwait() returned unexpected signal: %d", signo);
457
458     return NGX_ERROR;
459 }
460
461
462 static ngx_int_t
463 ngx_rtsig_process_overflow(ngx_cycle_t *cycle, ngx_msec_t timer,
464     ngx_uint_t flags)
465 {
466     int                name[2], rtsig_max, rtsig_nr, events, ready;
467     size_t             len;
468     ngx_err_t          err;
469     ngx_uint_t         tested, n, i;
470     ngx_event_t       *rev, *wev, **queue;
471     ngx_connection_t  *c;
472     ngx_rtsig_conf_t  *rtscf;
473
474     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
475                    "rtsig process overflow");
476
477     rtscf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_rtsig_module);
478
479     tested = 0;
480
481     for ( ;; ) {
482
483         n = 0;
484         while (n < rtscf->overflow_events) {
485
486             if (overflow_current == cycle->connection_n) {
487                 break;
488             }
489
490             c = cycle->files[overflow_current++];
491
492             if (c == NULL || c->fd == -1) {
493                 continue;
494             }
495
496             events = 0;
497
498             if (c->read->active && c->read->handler) {
499                 events |= POLLIN;
500             }
501
502             if (c->write->active && c->write->handler) {
503                 events |= POLLOUT;
504             }
505
506             if (events == 0) {
507                 continue;
508             }
509
510             overflow_list[n].fd = c->fd;
511             overflow_list[n].events = events;
512             overflow_list[n].revents = 0;
513             n++;
514         }
515
516         if (n == 0) {
517             break;
518         }
519
520         for ( ;; ) {
521             ready = poll(overflow_list, n, 0);
522
523             ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
524                            "rtsig overflow poll:%d", ready);
525
526             if (ready == -1) {
527                 err = ngx_errno;
528                 ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT,
529                               cycle->log, 0,
530                               "poll() failed while the overflow recover");
531
532                 if (err == NGX_EINTR) {
533                     continue;
534                 }
535             }
536
537             break;
538         }
539
540         if (ready <= 0) {
541             continue;
542         }
543
544         ngx_mutex_lock(ngx_posted_events_mutex);
545
546         for (i = 0; i < n; i++) {
547             c = cycle->files[overflow_list[i].fd];
548
549             if (c == NULL) {
550                 continue;
551             }
552
553             rev = c->read;
554
555             if (rev->active
556                 && !rev->closed
557                 && rev->handler
558                 && (overflow_list[i].revents
559                                           & (POLLIN|POLLERR|POLLHUP|POLLNVAL)))
560             {
561                 tested++;
562
563                 if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
564                     rev->posted_ready = 1;
565
566                 } else {
567                     rev->ready = 1;
568                 }
569
570                 if (flags & NGX_POST_EVENTS) {
571                     queue = (ngx_event_t **) (rev->accept ?
572                                &ngx_posted_accept_events : &ngx_posted_events);
573
574                     ngx_locked_post_event(rev, queue);
575
576                 } else {
577                     rev->handler(rev);
578                 }
579             }
580
581             wev = c->write;
582
583             if (wev->active
584                 && !wev->closed
585                 && wev->handler
586                 && (overflow_list[i].revents
587                                          & (POLLOUT|POLLERR|POLLHUP|POLLNVAL)))
588             {
589                 tested++;
590
591                 if (flags & NGX_POST_THREAD_EVENTS) {
592                     wev->posted_ready = 1;
593
594                 } else {
595                     wev->ready = 1;
596                 }
597
598                 if (flags & NGX_POST_EVENTS) {
599                     ngx_locked_post_event(wev, &ngx_posted_events);
600
601                 } else {
602                     wev->handler(wev);
603                 }
604             }
605         }
606
607         ngx_mutex_unlock(ngx_posted_events_mutex);
608
609         if (tested >= rtscf->overflow_test) {
610
611             if (ngx_linux_rtsig_max) {
612
613                 /*
614                  * Check the current rt queue length to prevent
615                  * the new overflow.
616                  *
617                  * learn the "/proc/sys/kernel/rtsig-max" value because
618                  * it can be changed since the last checking
619                  */
620
621                 name[0] = CTL_KERN;
622                 name[1] = KERN_RTSIGMAX;
623                 len = sizeof(rtsig_max);
624
625                 if (sysctl(name, 2, &rtsig_max, &len, NULL, 0) == -1) {
626                     ngx_log_error(NGX_LOG_ALERT, cycle->log, errno,
627                                   "sysctl(KERN_RTSIGMAX) failed");
628                     return NGX_ERROR;
629                 }
630
631                 /* name[0] = CTL_KERN; */
632                 name[1] = KERN_RTSIGNR;
633                 len = sizeof(rtsig_nr);
634
635                 if (sysctl(name, 2, &rtsig_nr, &len, NULL, 0) == -1) {
636                     ngx_log_error(NGX_LOG_ALERT, cycle->log, errno,
637                                   "sysctl(KERN_RTSIGNR) failed");
638                     return NGX_ERROR;
639                 }
640
641                 /*
642                  * drain the rt signal queue if the /"proc/sys/kernel/rtsig-nr"
643                  * is bigger than
644                  *    "/proc/sys/kernel/rtsig-max" / "rtsig_overflow_threshold"
645                  */
646
647                 if (rtsig_max / (int) rtscf->overflow_threshold < rtsig_nr) {
648                     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
649                                    "rtsig queue state: %d/%d",
650                                    rtsig_nr, rtsig_max);
651                     while (ngx_rtsig_process_events(cycle, 0, flags) == NGX_OK)
652                     {
653                         /* void */
654                     }
655                 }
656
657             } else {
658
659                 /*
660                  * Linux has not KERN_RTSIGMAX since 2.6.6-mm2
661                  * so drain the rt signal queue unconditionally
662                  */
663
664                 while (ngx_rtsig_process_events(cycle, 0, flags) == NGX_OK) {
665                     /* void */
666                 }
667             }
668
669             tested = 0;
670         }
671     }
672
673     if (flags & NGX_UPDATE_TIME) {
674         ngx_time_update(0, 0);
675     }
676
677     ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
678                   "rt signal queue overflow recovered");
679
680     overflow = 0;
681     ngx_event_actions.process_events = ngx_rtsig_process_events;
682
683     return NGX_OK;
684 }
685
686
687 static void *
688 ngx_rtsig_create_conf(ngx_cycle_t *cycle)
689 {
690     ngx_rtsig_conf_t  *rtscf;
691
692     rtscf = ngx_palloc(cycle->pool, sizeof(ngx_rtsig_conf_t));
693     if (rtscf == NULL) {
694         return NGX_CONF_ERROR;
695     }
696
697     rtscf->signo = NGX_CONF_UNSET;
698     rtscf->overflow_events = NGX_CONF_UNSET;
699     rtscf->overflow_test = NGX_CONF_UNSET;
700     rtscf->overflow_threshold = NGX_CONF_UNSET;
701
702     return rtscf;
703 }
704
705
706 static char *
707 ngx_rtsig_init_conf(ngx_cycle_t *cycle, void *conf)
708 {
709     ngx_rtsig_conf_t  *rtscf = conf;
710
711     /* LinuxThreads use the first 3 RT signals */
712     ngx_conf_init_uint_value(rtscf->signo, SIGRTMIN + 10);
713
714     ngx_conf_init_uint_value(rtscf->overflow_events, 16);
715     ngx_conf_init_uint_value(rtscf->overflow_test, 32);
716     ngx_conf_init_uint_value(rtscf->overflow_threshold, 10);
717
718     return NGX_CONF_OK;
719 }
720
721
722 static char *
723 ngx_check_ngx_overflow_threshold_bounds(ngx_conf_t *cf, void *post, void *data)
724 {
725     if (ngx_linux_rtsig_max) {
726         return ngx_conf_check_num_bounds(cf, post, data);
727     }
728
729     ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
730                        "\"rtsig_overflow_threshold\" is not supported "
731                        "since Linux 2.6.6-mm2, ignored");
732
733     return NGX_CONF_OK;
734 }