Coverage Report

Created: 2025-10-13 06:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/unit/src/nxt_signal.c
Line
Count
Source
1
2
/*
3
 * Copyright (C) Igor Sysoev
4
 * Copyright (C) NGINX, Inc.
5
 */
6
7
#include <nxt_main.h>
8
9
10
/*
11
 * Signals are handled only via a main thread event engine work queue.
12
 * There are three ways to route signals to the work queue:
13
 *
14
 * 1) Using signal event notifications if an event facility supports it:
15
 *    kqueue and epoll/signalfd.  This method is used regardless of thread mode.
16
 *
17
 * 2) Multi-threaded mode: a dedicated signal thread which waits in sigwait()
18
 *    and post a signal number to the main thread event engine.
19
 *
20
 * 3) Single-threaded mode: a signal handler which posts a signal number
21
 *    to the event engine.
22
 */
23
24
25
static nxt_int_t nxt_signal_action(int signo, void (*handler)(int));
26
static void nxt_signal_thread(void *data);
27
28
29
nxt_event_signals_t *
30
nxt_event_engine_signals(const nxt_sig_event_t *sigev)
31
0
{
32
0
    nxt_event_signals_t  *signals;
33
34
0
    signals = nxt_zalloc(sizeof(nxt_event_signals_t));
35
0
    if (signals == NULL) {
36
0
        return NULL;
37
0
    }
38
39
0
    signals->sigev = sigev;
40
41
0
    if (nxt_signal_action(SIGSYS, SIG_IGN) != NXT_OK) {
42
0
        goto fail;
43
0
    }
44
45
0
    if (nxt_signal_action(SIGPIPE, SIG_IGN) != NXT_OK) {
46
0
        goto fail;
47
0
    }
48
49
0
    sigemptyset(&signals->sigmask);
50
51
0
    while (sigev->signo != 0) {
52
0
        sigaddset(&signals->sigmask, sigev->signo);
53
0
        sigev++;
54
0
    }
55
56
0
    if (sigprocmask(SIG_BLOCK, &signals->sigmask, NULL) != 0) {
57
0
        nxt_main_log_alert("sigprocmask(SIG_BLOCK) failed %E", nxt_errno);
58
0
        goto fail;
59
0
    }
60
61
0
    return signals;
62
63
0
fail:
64
65
0
    nxt_free(signals);
66
67
0
    return NULL;
68
0
}
69
70
71
static nxt_int_t
72
nxt_signal_action(int signo, void (*handler)(int))
73
0
{
74
0
    struct sigaction  sa;
75
76
0
    nxt_memzero(&sa, sizeof(struct sigaction));
77
0
    sigemptyset(&sa.sa_mask);
78
0
    sa.sa_handler = handler;
79
80
0
    if (sigaction(signo, &sa, NULL) == 0) {
81
0
        return NXT_OK;
82
0
    }
83
84
0
    nxt_main_log_alert("sigaction(%d) failed %E", signo, nxt_errno);
85
86
0
    return NXT_ERROR;
87
0
}
88
89
90
static void
91
nxt_signal_handler(int signo)
92
0
{
93
0
    nxt_thread_t  *thr;
94
95
0
    thr = nxt_thread();
96
97
    /* Thread is running in a single context now. */
98
0
    thr->time.signal++;
99
100
0
    nxt_thread_time_update(thr);
101
102
0
    nxt_main_log_error(NXT_LOG_INFO, "signal handler: %d", signo);
103
104
0
    nxt_event_engine_signal(thr->engine, signo);
105
106
0
    thr->time.signal--;
107
0
}
108
109
110
nxt_int_t
111
nxt_signal_thread_start(nxt_event_engine_t *engine)
112
0
{
113
0
    nxt_thread_link_t      *link;
114
0
    const nxt_sig_event_t  *sigev;
115
116
0
    if (engine->signals->process == nxt_pid) {
117
0
        return NXT_OK;
118
0
    }
119
120
0
    if (sigprocmask(SIG_BLOCK, &engine->signals->sigmask, NULL) != 0) {
121
0
        nxt_main_log_alert("sigprocmask(SIG_BLOCK) failed %E", nxt_errno);
122
0
        return NXT_ERROR;
123
0
    }
124
125
    /*
126
     * kqueue sets signal handlers to SIG_IGN and sigwait() ignores
127
     * them after the switch of event facility from "kqueue" to "select".
128
     */
129
130
0
    for (sigev = engine->signals->sigev; sigev->signo != 0; sigev++) {
131
0
        if (nxt_signal_action(sigev->signo, nxt_signal_handler) != NXT_OK) {
132
0
            return NXT_ERROR;
133
0
        }
134
0
    }
135
136
0
    link = nxt_zalloc(sizeof(nxt_thread_link_t));
137
138
0
    if (nxt_fast_path(link != NULL)) {
139
0
        link->start = nxt_signal_thread;
140
0
        link->work.data = engine;
141
142
0
        if (nxt_thread_create(&engine->signals->thread, link) == NXT_OK) {
143
0
            engine->signals->process = nxt_pid;
144
0
            return NXT_OK;
145
0
        }
146
0
    }
147
148
0
    return NXT_ERROR;
149
0
}
150
151
152
static void
153
nxt_signal_thread(void *data)
154
0
{
155
0
    int                 signo;
156
0
    nxt_err_t           err;
157
0
    nxt_thread_t        *thr;
158
0
    nxt_event_engine_t  *engine;
159
160
0
    engine = data;
161
162
0
    thr = nxt_thread();
163
164
0
    nxt_main_log_debug("signal thread");
165
166
0
    for ( ;; ) {
167
0
        err = sigwait(&engine->signals->sigmask, &signo);
168
169
0
        nxt_thread_time_update(thr);
170
171
0
        if (nxt_fast_path(err == 0)) {
172
0
            nxt_main_log_error(NXT_LOG_INFO, "signo: %d", signo);
173
174
0
            nxt_event_engine_signal(engine, signo);
175
176
0
        } else {
177
0
            nxt_main_log_alert("sigwait() failed %E", err);
178
0
        }
179
0
    }
180
0
}
181
182
183
void
184
nxt_signal_thread_stop(nxt_event_engine_t *engine)
185
0
{
186
0
    nxt_thread_handle_t  thread;
187
188
0
    thread = engine->signals->thread;
189
190
0
    nxt_thread_cancel(thread);
191
0
    nxt_thread_wait(thread);
192
0
}