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)); 260Sigor@sysoev.ru 270Sigor@sysoev.ru 280Sigor@sysoev.ru nxt_event_signals_t * 29*12Sigor@sysoev.ru nxt_event_engine_signals(const nxt_sig_event_t *sigev) 300Sigor@sysoev.ru { 310Sigor@sysoev.ru nxt_event_signals_t *signals; 320Sigor@sysoev.ru 330Sigor@sysoev.ru signals = nxt_zalloc(sizeof(nxt_event_signals_t)); 340Sigor@sysoev.ru if (signals == NULL) { 350Sigor@sysoev.ru return NULL; 360Sigor@sysoev.ru } 370Sigor@sysoev.ru 380Sigor@sysoev.ru signals->sigev = sigev; 390Sigor@sysoev.ru 400Sigor@sysoev.ru if (nxt_signal_action(SIGSYS, SIG_IGN) != NXT_OK) { 410Sigor@sysoev.ru goto fail; 420Sigor@sysoev.ru } 430Sigor@sysoev.ru 440Sigor@sysoev.ru if (nxt_signal_action(SIGPIPE, SIG_IGN) != NXT_OK) { 450Sigor@sysoev.ru goto fail; 460Sigor@sysoev.ru } 470Sigor@sysoev.ru 480Sigor@sysoev.ru sigemptyset(&signals->sigmask); 490Sigor@sysoev.ru 500Sigor@sysoev.ru while (sigev->signo != 0) { 510Sigor@sysoev.ru sigaddset(&signals->sigmask, sigev->signo); 520Sigor@sysoev.ru sigev++; 530Sigor@sysoev.ru } 540Sigor@sysoev.ru 550Sigor@sysoev.ru if (sigprocmask(SIG_BLOCK, &signals->sigmask, NULL) != 0) { 560Sigor@sysoev.ru nxt_main_log_alert("sigprocmask(SIG_BLOCK) failed %E", nxt_errno); 570Sigor@sysoev.ru goto fail; 580Sigor@sysoev.ru } 590Sigor@sysoev.ru 600Sigor@sysoev.ru return signals; 610Sigor@sysoev.ru 620Sigor@sysoev.ru fail: 630Sigor@sysoev.ru 640Sigor@sysoev.ru nxt_free(signals); 650Sigor@sysoev.ru 660Sigor@sysoev.ru return NULL; 670Sigor@sysoev.ru } 680Sigor@sysoev.ru 690Sigor@sysoev.ru 700Sigor@sysoev.ru static nxt_int_t 710Sigor@sysoev.ru nxt_signal_action(int signo, void (*handler)(int)) 720Sigor@sysoev.ru { 730Sigor@sysoev.ru struct sigaction sa; 740Sigor@sysoev.ru 750Sigor@sysoev.ru nxt_memzero(&sa, sizeof(struct sigaction)); 760Sigor@sysoev.ru sigemptyset(&sa.sa_mask); 770Sigor@sysoev.ru sa.sa_handler = handler; 780Sigor@sysoev.ru 790Sigor@sysoev.ru if (sigaction(signo, &sa, NULL) == 0) { 800Sigor@sysoev.ru return NXT_OK; 810Sigor@sysoev.ru } 820Sigor@sysoev.ru 830Sigor@sysoev.ru nxt_main_log_alert("sigaction(%d) failed %E", signo, nxt_errno); 840Sigor@sysoev.ru 850Sigor@sysoev.ru return NXT_ERROR; 860Sigor@sysoev.ru } 870Sigor@sysoev.ru 880Sigor@sysoev.ru 890Sigor@sysoev.ru static void 900Sigor@sysoev.ru nxt_signal_handler(int signo) 910Sigor@sysoev.ru { 920Sigor@sysoev.ru nxt_thread_t *thr; 930Sigor@sysoev.ru 940Sigor@sysoev.ru thr = nxt_thread(); 950Sigor@sysoev.ru 960Sigor@sysoev.ru /* Thread is running in a single context now. */ 970Sigor@sysoev.ru thr->time.signal++; 980Sigor@sysoev.ru 990Sigor@sysoev.ru nxt_thread_time_update(thr); 1000Sigor@sysoev.ru 1010Sigor@sysoev.ru nxt_main_log_error(NXT_LOG_INFO, "signal handler: %d", signo); 1020Sigor@sysoev.ru 1030Sigor@sysoev.ru nxt_event_engine_signal(thr->engine, signo); 1040Sigor@sysoev.ru 1050Sigor@sysoev.ru thr->time.signal--; 1060Sigor@sysoev.ru } 1070Sigor@sysoev.ru 1080Sigor@sysoev.ru 1090Sigor@sysoev.ru #if (NXT_THREADS) 1100Sigor@sysoev.ru 1110Sigor@sysoev.ru static void nxt_signal_thread(void *data); 1120Sigor@sysoev.ru 1130Sigor@sysoev.ru 1140Sigor@sysoev.ru nxt_int_t 1150Sigor@sysoev.ru nxt_signal_thread_start(nxt_event_engine_t *engine) 1160Sigor@sysoev.ru { 1170Sigor@sysoev.ru nxt_thread_link_t *link; 118*12Sigor@sysoev.ru const nxt_sig_event_t *sigev; 1190Sigor@sysoev.ru 1200Sigor@sysoev.ru if (engine->signals->process == nxt_pid) { 1210Sigor@sysoev.ru return NXT_OK; 1220Sigor@sysoev.ru } 1230Sigor@sysoev.ru 1240Sigor@sysoev.ru if (sigprocmask(SIG_BLOCK, &engine->signals->sigmask, NULL) != 0) { 1250Sigor@sysoev.ru nxt_main_log_alert("sigprocmask(SIG_BLOCK) failed %E", nxt_errno); 1260Sigor@sysoev.ru return NXT_ERROR; 1270Sigor@sysoev.ru } 1280Sigor@sysoev.ru 1290Sigor@sysoev.ru /* 1300Sigor@sysoev.ru * kqueue sets signal handlers to SIG_IGN and sigwait() ignores 1310Sigor@sysoev.ru * them after the switch of event facility from "kqueue" to "select". 1320Sigor@sysoev.ru */ 1330Sigor@sysoev.ru 1340Sigor@sysoev.ru for (sigev = engine->signals->sigev; sigev->signo != 0; sigev++) { 1350Sigor@sysoev.ru if (nxt_signal_action(sigev->signo, nxt_signal_handler) != NXT_OK) { 1360Sigor@sysoev.ru return NXT_ERROR; 1370Sigor@sysoev.ru } 1380Sigor@sysoev.ru } 1390Sigor@sysoev.ru 1400Sigor@sysoev.ru link = nxt_zalloc(sizeof(nxt_thread_link_t)); 1410Sigor@sysoev.ru 1420Sigor@sysoev.ru if (nxt_fast_path(link != NULL)) { 1430Sigor@sysoev.ru link->start = nxt_signal_thread; 1440Sigor@sysoev.ru link->data = engine; 1450Sigor@sysoev.ru 1460Sigor@sysoev.ru if (nxt_thread_create(&engine->signals->thread, link) == NXT_OK) { 1470Sigor@sysoev.ru engine->signals->process = nxt_pid; 1480Sigor@sysoev.ru return NXT_OK; 1490Sigor@sysoev.ru } 1500Sigor@sysoev.ru } 1510Sigor@sysoev.ru 1520Sigor@sysoev.ru return NXT_ERROR; 1530Sigor@sysoev.ru } 1540Sigor@sysoev.ru 1550Sigor@sysoev.ru 1560Sigor@sysoev.ru static void 1570Sigor@sysoev.ru nxt_signal_thread(void *data) 1580Sigor@sysoev.ru { 1590Sigor@sysoev.ru int signo; 1600Sigor@sysoev.ru nxt_err_t err; 1610Sigor@sysoev.ru nxt_thread_t *thr; 1620Sigor@sysoev.ru nxt_event_engine_t *engine; 1630Sigor@sysoev.ru 1640Sigor@sysoev.ru engine = data; 1650Sigor@sysoev.ru 1660Sigor@sysoev.ru thr = nxt_thread(); 1670Sigor@sysoev.ru 1680Sigor@sysoev.ru nxt_main_log_debug("signal thread"); 1690Sigor@sysoev.ru 1700Sigor@sysoev.ru for ( ;; ) { 1710Sigor@sysoev.ru err = sigwait(&engine->signals->sigmask, &signo); 1720Sigor@sysoev.ru 1730Sigor@sysoev.ru nxt_thread_time_update(thr); 1740Sigor@sysoev.ru 1750Sigor@sysoev.ru if (nxt_fast_path(err == 0)) { 1760Sigor@sysoev.ru nxt_main_log_error(NXT_LOG_INFO, "signo: %d", signo); 1770Sigor@sysoev.ru 1780Sigor@sysoev.ru nxt_event_engine_signal(engine, signo); 1790Sigor@sysoev.ru 1800Sigor@sysoev.ru } else { 1810Sigor@sysoev.ru nxt_main_log_alert("sigwait() failed %E", err); 1820Sigor@sysoev.ru } 1830Sigor@sysoev.ru } 1840Sigor@sysoev.ru } 1850Sigor@sysoev.ru 1860Sigor@sysoev.ru 1870Sigor@sysoev.ru void 1880Sigor@sysoev.ru nxt_signal_thread_stop(nxt_event_engine_t *engine) 1890Sigor@sysoev.ru { 1900Sigor@sysoev.ru nxt_thread_handle_t thread; 1910Sigor@sysoev.ru 1920Sigor@sysoev.ru thread = engine->signals->thread; 1930Sigor@sysoev.ru 1940Sigor@sysoev.ru nxt_thread_cancel(thread); 1950Sigor@sysoev.ru nxt_thread_wait(thread); 1960Sigor@sysoev.ru } 1970Sigor@sysoev.ru 1980Sigor@sysoev.ru 1990Sigor@sysoev.ru #else /* !(NXT_THREADS) */ 2000Sigor@sysoev.ru 2010Sigor@sysoev.ru 2020Sigor@sysoev.ru nxt_int_t 2030Sigor@sysoev.ru nxt_signal_handlers_start(nxt_event_engine_t *engine) 2040Sigor@sysoev.ru { 205*12Sigor@sysoev.ru const nxt_sig_event_t *sigev; 2060Sigor@sysoev.ru 2070Sigor@sysoev.ru for (sigev = engine->signals->sigev; sigev->signo != 0; sigev++) { 2080Sigor@sysoev.ru if (nxt_signal_action(sigev->signo, nxt_signal_handler) != NXT_OK) { 2090Sigor@sysoev.ru return NXT_ERROR; 2100Sigor@sysoev.ru } 2110Sigor@sysoev.ru } 2120Sigor@sysoev.ru 2130Sigor@sysoev.ru if (sigprocmask(SIG_UNBLOCK, &engine->signals->sigmask, NULL) != 0) { 2140Sigor@sysoev.ru nxt_main_log_alert("sigprocmask(SIG_UNBLOCK) failed %E", nxt_errno); 2150Sigor@sysoev.ru return NXT_ERROR; 2160Sigor@sysoev.ru } 2170Sigor@sysoev.ru 2180Sigor@sysoev.ru return NXT_OK; 2190Sigor@sysoev.ru } 2200Sigor@sysoev.ru 2210Sigor@sysoev.ru 2220Sigor@sysoev.ru void 2230Sigor@sysoev.ru nxt_signal_handlers_stop(nxt_event_engine_t *engine) 2240Sigor@sysoev.ru { 2250Sigor@sysoev.ru if (sigprocmask(SIG_BLOCK, &engine->signals->sigmask, NULL) != 0) { 2260Sigor@sysoev.ru nxt_main_log_alert("sigprocmask(SIG_BLOCK) failed %E", nxt_errno); 2270Sigor@sysoev.ru } 2280Sigor@sysoev.ru } 2290Sigor@sysoev.ru 2300Sigor@sysoev.ru #endif 231