xref: /unit/src/nxt_signal.c (revision 223:bf98efe2c55c)
10Sigor@sysoev.ru 
20Sigor@sysoev.ru /*
30Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
40Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
50Sigor@sysoev.ru  */
60Sigor@sysoev.ru 
70Sigor@sysoev.ru #include <nxt_main.h>
80Sigor@sysoev.ru 
90Sigor@sysoev.ru 
100Sigor@sysoev.ru /*
110Sigor@sysoev.ru  * Signals are handled only via a main thread event engine work queue.
120Sigor@sysoev.ru  * There are three ways to route signals to the work queue:
130Sigor@sysoev.ru  *
140Sigor@sysoev.ru  * 1) Using signal event notifications if an event facility supports it:
150Sigor@sysoev.ru  *    kqueue and epoll/signalfd.  This method is used regardless of thread mode.
160Sigor@sysoev.ru  *
170Sigor@sysoev.ru  * 2) Multi-threaded mode: a dedicated signal thread which waits in sigwait()
180Sigor@sysoev.ru  *    and post a signal number to the main thread event engine.
190Sigor@sysoev.ru  *
200Sigor@sysoev.ru  * 3) Single-threaded mode: a signal handler which posts a signal number
210Sigor@sysoev.ru  *    to the event engine.
220Sigor@sysoev.ru  */
230Sigor@sysoev.ru 
240Sigor@sysoev.ru 
250Sigor@sysoev.ru static nxt_int_t nxt_signal_action(int signo, void (*handler)(int));
26*223Sigor@sysoev.ru static void nxt_signal_thread(void *data);
270Sigor@sysoev.ru 
280Sigor@sysoev.ru 
290Sigor@sysoev.ru nxt_event_signals_t *
nxt_event_engine_signals(const nxt_sig_event_t * sigev)3012Sigor@sysoev.ru nxt_event_engine_signals(const nxt_sig_event_t *sigev)
310Sigor@sysoev.ru {
320Sigor@sysoev.ru     nxt_event_signals_t  *signals;
330Sigor@sysoev.ru 
340Sigor@sysoev.ru     signals = nxt_zalloc(sizeof(nxt_event_signals_t));
350Sigor@sysoev.ru     if (signals == NULL) {
360Sigor@sysoev.ru         return NULL;
370Sigor@sysoev.ru     }
380Sigor@sysoev.ru 
390Sigor@sysoev.ru     signals->sigev = sigev;
400Sigor@sysoev.ru 
410Sigor@sysoev.ru     if (nxt_signal_action(SIGSYS, SIG_IGN) != NXT_OK) {
420Sigor@sysoev.ru         goto fail;
430Sigor@sysoev.ru     }
440Sigor@sysoev.ru 
450Sigor@sysoev.ru     if (nxt_signal_action(SIGPIPE, SIG_IGN) != NXT_OK) {
460Sigor@sysoev.ru         goto fail;
470Sigor@sysoev.ru     }
480Sigor@sysoev.ru 
490Sigor@sysoev.ru     sigemptyset(&signals->sigmask);
500Sigor@sysoev.ru 
510Sigor@sysoev.ru     while (sigev->signo != 0) {
520Sigor@sysoev.ru         sigaddset(&signals->sigmask, sigev->signo);
530Sigor@sysoev.ru         sigev++;
540Sigor@sysoev.ru     }
550Sigor@sysoev.ru 
560Sigor@sysoev.ru     if (sigprocmask(SIG_BLOCK, &signals->sigmask, NULL) != 0) {
570Sigor@sysoev.ru         nxt_main_log_alert("sigprocmask(SIG_BLOCK) failed %E", nxt_errno);
580Sigor@sysoev.ru         goto fail;
590Sigor@sysoev.ru     }
600Sigor@sysoev.ru 
610Sigor@sysoev.ru     return signals;
620Sigor@sysoev.ru 
630Sigor@sysoev.ru fail:
640Sigor@sysoev.ru 
650Sigor@sysoev.ru     nxt_free(signals);
660Sigor@sysoev.ru 
670Sigor@sysoev.ru     return NULL;
680Sigor@sysoev.ru }
690Sigor@sysoev.ru 
700Sigor@sysoev.ru 
710Sigor@sysoev.ru static nxt_int_t
nxt_signal_action(int signo,void (* handler)(int))720Sigor@sysoev.ru nxt_signal_action(int signo, void (*handler)(int))
730Sigor@sysoev.ru {
740Sigor@sysoev.ru     struct sigaction  sa;
750Sigor@sysoev.ru 
760Sigor@sysoev.ru     nxt_memzero(&sa, sizeof(struct sigaction));
770Sigor@sysoev.ru     sigemptyset(&sa.sa_mask);
780Sigor@sysoev.ru     sa.sa_handler = handler;
790Sigor@sysoev.ru 
800Sigor@sysoev.ru     if (sigaction(signo, &sa, NULL) == 0) {
810Sigor@sysoev.ru         return NXT_OK;
820Sigor@sysoev.ru     }
830Sigor@sysoev.ru 
840Sigor@sysoev.ru     nxt_main_log_alert("sigaction(%d) failed %E", signo, nxt_errno);
850Sigor@sysoev.ru 
860Sigor@sysoev.ru     return NXT_ERROR;
870Sigor@sysoev.ru }
880Sigor@sysoev.ru 
890Sigor@sysoev.ru 
900Sigor@sysoev.ru static void
nxt_signal_handler(int signo)910Sigor@sysoev.ru nxt_signal_handler(int signo)
920Sigor@sysoev.ru {
930Sigor@sysoev.ru     nxt_thread_t  *thr;
940Sigor@sysoev.ru 
950Sigor@sysoev.ru     thr = nxt_thread();
960Sigor@sysoev.ru 
970Sigor@sysoev.ru     /* Thread is running in a single context now. */
980Sigor@sysoev.ru     thr->time.signal++;
990Sigor@sysoev.ru 
1000Sigor@sysoev.ru     nxt_thread_time_update(thr);
1010Sigor@sysoev.ru 
1020Sigor@sysoev.ru     nxt_main_log_error(NXT_LOG_INFO, "signal handler: %d", signo);
1030Sigor@sysoev.ru 
1040Sigor@sysoev.ru     nxt_event_engine_signal(thr->engine, signo);
1050Sigor@sysoev.ru 
1060Sigor@sysoev.ru     thr->time.signal--;
1070Sigor@sysoev.ru }
1080Sigor@sysoev.ru 
1090Sigor@sysoev.ru 
1100Sigor@sysoev.ru nxt_int_t
nxt_signal_thread_start(nxt_event_engine_t * engine)1110Sigor@sysoev.ru nxt_signal_thread_start(nxt_event_engine_t *engine)
1120Sigor@sysoev.ru {
1130Sigor@sysoev.ru     nxt_thread_link_t      *link;
11412Sigor@sysoev.ru     const nxt_sig_event_t  *sigev;
1150Sigor@sysoev.ru 
1160Sigor@sysoev.ru     if (engine->signals->process == nxt_pid) {
1170Sigor@sysoev.ru         return NXT_OK;
1180Sigor@sysoev.ru     }
1190Sigor@sysoev.ru 
1200Sigor@sysoev.ru     if (sigprocmask(SIG_BLOCK, &engine->signals->sigmask, NULL) != 0) {
1210Sigor@sysoev.ru         nxt_main_log_alert("sigprocmask(SIG_BLOCK) failed %E", nxt_errno);
1220Sigor@sysoev.ru         return NXT_ERROR;
1230Sigor@sysoev.ru     }
1240Sigor@sysoev.ru 
1250Sigor@sysoev.ru     /*
1260Sigor@sysoev.ru      * kqueue sets signal handlers to SIG_IGN and sigwait() ignores
1270Sigor@sysoev.ru      * them after the switch of event facility from "kqueue" to "select".
1280Sigor@sysoev.ru      */
1290Sigor@sysoev.ru 
1300Sigor@sysoev.ru     for (sigev = engine->signals->sigev; sigev->signo != 0; sigev++) {
1310Sigor@sysoev.ru         if (nxt_signal_action(sigev->signo, nxt_signal_handler) != NXT_OK) {
1320Sigor@sysoev.ru             return NXT_ERROR;
1330Sigor@sysoev.ru         }
1340Sigor@sysoev.ru     }
1350Sigor@sysoev.ru 
1360Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
1370Sigor@sysoev.ru 
1380Sigor@sysoev.ru     if (nxt_fast_path(link != NULL)) {
1390Sigor@sysoev.ru         link->start = nxt_signal_thread;
14053Sigor@sysoev.ru         link->work.data = engine;
1410Sigor@sysoev.ru 
1420Sigor@sysoev.ru         if (nxt_thread_create(&engine->signals->thread, link) == NXT_OK) {
1430Sigor@sysoev.ru             engine->signals->process = nxt_pid;
1440Sigor@sysoev.ru             return NXT_OK;
1450Sigor@sysoev.ru         }
1460Sigor@sysoev.ru     }
1470Sigor@sysoev.ru 
1480Sigor@sysoev.ru     return NXT_ERROR;
1490Sigor@sysoev.ru }
1500Sigor@sysoev.ru 
1510Sigor@sysoev.ru 
1520Sigor@sysoev.ru static void
nxt_signal_thread(void * data)1530Sigor@sysoev.ru nxt_signal_thread(void *data)
1540Sigor@sysoev.ru {
1550Sigor@sysoev.ru     int                 signo;
1560Sigor@sysoev.ru     nxt_err_t           err;
1570Sigor@sysoev.ru     nxt_thread_t        *thr;
1580Sigor@sysoev.ru     nxt_event_engine_t  *engine;
1590Sigor@sysoev.ru 
1600Sigor@sysoev.ru     engine = data;
1610Sigor@sysoev.ru 
1620Sigor@sysoev.ru     thr = nxt_thread();
1630Sigor@sysoev.ru 
1640Sigor@sysoev.ru     nxt_main_log_debug("signal thread");
1650Sigor@sysoev.ru 
1660Sigor@sysoev.ru     for ( ;; ) {
1670Sigor@sysoev.ru         err = sigwait(&engine->signals->sigmask, &signo);
1680Sigor@sysoev.ru 
1690Sigor@sysoev.ru         nxt_thread_time_update(thr);
1700Sigor@sysoev.ru 
1710Sigor@sysoev.ru         if (nxt_fast_path(err == 0)) {
1720Sigor@sysoev.ru             nxt_main_log_error(NXT_LOG_INFO, "signo: %d", signo);
1730Sigor@sysoev.ru 
1740Sigor@sysoev.ru             nxt_event_engine_signal(engine, signo);
1750Sigor@sysoev.ru 
1760Sigor@sysoev.ru         } else {
1770Sigor@sysoev.ru             nxt_main_log_alert("sigwait() failed %E", err);
1780Sigor@sysoev.ru         }
1790Sigor@sysoev.ru     }
1800Sigor@sysoev.ru }
1810Sigor@sysoev.ru 
1820Sigor@sysoev.ru 
1830Sigor@sysoev.ru void
nxt_signal_thread_stop(nxt_event_engine_t * engine)1840Sigor@sysoev.ru nxt_signal_thread_stop(nxt_event_engine_t *engine)
1850Sigor@sysoev.ru {
1860Sigor@sysoev.ru     nxt_thread_handle_t  thread;
1870Sigor@sysoev.ru 
1880Sigor@sysoev.ru     thread = engine->signals->thread;
1890Sigor@sysoev.ru 
1900Sigor@sysoev.ru     nxt_thread_cancel(thread);
1910Sigor@sysoev.ru     nxt_thread_wait(thread);
1920Sigor@sysoev.ru }
193