/src/haproxy/src/signal.c
Line | Count | Source |
1 | | /* |
2 | | * Asynchronous signal delivery functions. |
3 | | * |
4 | | * Copyright 2000-2010 Willy Tarreau <w@1wt.eu> |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU General Public License |
8 | | * as published by the Free Software Foundation; either version |
9 | | * 2 of the License, or (at your option) any later version. |
10 | | * |
11 | | */ |
12 | | |
13 | | #include <signal.h> |
14 | | #include <string.h> |
15 | | |
16 | | #include <haproxy/errors.h> |
17 | | #include <haproxy/signal.h> |
18 | | #include <haproxy/task.h> |
19 | | |
20 | | /* Principle : we keep an in-order list of the first occurrence of all received |
21 | | * signals. All occurrences of a same signal are grouped though. The signal |
22 | | * queue does not need to be deeper than the number of signals we can handle. |
23 | | * The handlers will be called asynchronously with the signal number. They can |
24 | | * check themselves the number of calls by checking the descriptor this signal. |
25 | | */ |
26 | | |
27 | | int signal_queue_len; /* length of signal queue, <= MAX_SIGNAL (1 entry per signal max) */ |
28 | | int signal_queue[MAX_SIGNAL]; /* in-order queue of received signals */ |
29 | | struct signal_descriptor signal_state[MAX_SIGNAL]; |
30 | | sigset_t blocked_sig; |
31 | | int signal_pending = 0; /* non-zero if t least one signal remains unprocessed */ |
32 | | |
33 | | DECLARE_STATIC_TYPED_POOL(pool_head_sig_handlers, "sig_handlers", struct sig_handler); |
34 | | |
35 | | /* Common signal handler, used by all signals. Received signals are queued. |
36 | | * Signal number zero has a specific status, as it cannot be delivered by the |
37 | | * system, any function may call it to perform asynchronous signal delivery. |
38 | | */ |
39 | | void signal_handler(int sig) |
40 | 0 | { |
41 | | /* inform callees to be careful, we're in a signal handler! */ |
42 | 0 | _HA_ATOMIC_OR(&th_ctx->flags, TH_FL_IN_SIG_HANDLER); |
43 | |
|
44 | 0 | if (sig < 0 || sig >= MAX_SIGNAL) { |
45 | | /* unhandled signal */ |
46 | 0 | signal(sig, SIG_IGN); |
47 | 0 | qfprintf(stderr, "Received unhandled signal %d. Signal has been disabled.\n", sig); |
48 | 0 | _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_IN_SIG_HANDLER); |
49 | 0 | return; |
50 | 0 | } |
51 | | |
52 | 0 | if (!signal_state[sig].count) { |
53 | | /* signal was not queued yet */ |
54 | 0 | if (signal_queue_len < MAX_SIGNAL) |
55 | 0 | signal_queue[signal_queue_len++] = sig; |
56 | 0 | else |
57 | 0 | qfprintf(stderr, "Signal %d : signal queue is unexpectedly full.\n", sig); |
58 | 0 | } |
59 | |
|
60 | 0 | signal_state[sig].count++; |
61 | 0 | if (sig) |
62 | 0 | signal(sig, signal_handler); /* re-arm signal */ |
63 | | |
64 | | /* If the thread is TH_FL_SLEEPING we need to wake it */ |
65 | 0 | wake_thread(tid); |
66 | 0 | _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_IN_SIG_HANDLER); |
67 | 0 | } |
68 | | |
69 | | /* Call handlers of all pending signals and clear counts and queue length. The |
70 | | * handlers may unregister themselves by calling signal_register() while they |
71 | | * are called, just like it is done with normal signal handlers. |
72 | | * Note that it is more efficient to call the inline version which checks the |
73 | | * queue length before getting here. |
74 | | */ |
75 | | void __signal_process_queue() |
76 | 0 | { |
77 | 0 | int sig, cur_pos = 0; |
78 | 0 | struct signal_descriptor *desc; |
79 | 0 | sigset_t old_sig; |
80 | | |
81 | | /* block signal delivery during processing */ |
82 | 0 | ha_sigmask(SIG_SETMASK, &blocked_sig, &old_sig); |
83 | | |
84 | | /* It is important that we scan the queue forwards so that we can |
85 | | * catch any signal that would have been queued by another signal |
86 | | * handler. That allows real signal handlers to redistribute signals |
87 | | * to tasks subscribed to signal zero. |
88 | | */ |
89 | 0 | for (cur_pos = 0; cur_pos < signal_queue_len; cur_pos++) { |
90 | 0 | sig = signal_queue[cur_pos]; |
91 | 0 | desc = &signal_state[sig]; |
92 | 0 | if (desc->count) { |
93 | 0 | struct sig_handler *sh, *shb; |
94 | 0 | list_for_each_entry_safe(sh, shb, &desc->handlers, list) { |
95 | 0 | if ((sh->flags & SIG_F_TYPE_FCT) && sh->handler) |
96 | 0 | ((void (*)(struct sig_handler *))sh->handler)(sh); |
97 | 0 | else if ((sh->flags & SIG_F_TYPE_TASK) && sh->handler) |
98 | 0 | task_wakeup(sh->handler, TASK_WOKEN_SIGNAL); |
99 | 0 | } |
100 | 0 | desc->count = 0; |
101 | 0 | } |
102 | 0 | } |
103 | 0 | signal_queue_len = 0; |
104 | | |
105 | | /* restore signal delivery */ |
106 | 0 | ha_sigmask(SIG_SETMASK, &old_sig, NULL); |
107 | 0 | } |
108 | | |
109 | | /* perform minimal initializations */ |
110 | | static void signal_init() |
111 | 0 | { |
112 | 0 | int sig; |
113 | | |
114 | | /* Need to register the handler for SIGINT explicitly, as we can be |
115 | | * laucned within the subshell and at background: |
116 | | * $ (./haproxy -f env4.cfg &). According to POSIX standard |
117 | | * (2.11. Signals and Error Handling), we will inherit from the subshell |
118 | | * in this case SIG_IGN signal handler for SIGINT and SIGQUIT. |
119 | | */ |
120 | 0 | signal(SIGINT, SIG_DFL); |
121 | 0 | signal_queue_len = 0; |
122 | 0 | memset(signal_queue, 0, sizeof(signal_queue)); |
123 | 0 | memset(signal_state, 0, sizeof(signal_state)); |
124 | |
|
125 | 0 | sigfillset(&blocked_sig); |
126 | 0 | sigdelset(&blocked_sig, SIGPROF); |
127 | | /* man sigprocmask: If SIGBUS, SIGFPE, SIGILL, or SIGSEGV are |
128 | | generated while they are blocked, the result is undefined, unless |
129 | | the signal was generated by kill(2), |
130 | | sigqueue(3), or raise(3). |
131 | | Do not ignore WDTSIG or DEBUGSIG either, or it may deadlock the |
132 | | watchdog */ |
133 | 0 | sigdelset(&blocked_sig, SIGBUS); |
134 | 0 | sigdelset(&blocked_sig, SIGFPE); |
135 | 0 | sigdelset(&blocked_sig, SIGILL); |
136 | 0 | sigdelset(&blocked_sig, SIGSEGV); |
137 | | #ifdef DEBUGSIG |
138 | | sigdelset(&blocked_sig, DEBUGSIG); |
139 | | #endif |
140 | | #ifdef WDTSIG |
141 | | sigdelset(&blocked_sig, WDTSIG); |
142 | | #endif |
143 | 0 | for (sig = 0; sig < MAX_SIGNAL; sig++) |
144 | 0 | LIST_INIT(&signal_state[sig].handlers); |
145 | 0 | } |
146 | | |
147 | | /* |
148 | | * This function should be called to unblock all signals |
149 | | */ |
150 | | void haproxy_unblock_signals() |
151 | 0 | { |
152 | 0 | sigset_t set; |
153 | | |
154 | | /* Ensure signals are not blocked. Some shells or service managers may |
155 | | * accidentally block all of our signals unfortunately, causing lots of |
156 | | * zombie processes to remain in the background during reloads. |
157 | | */ |
158 | 0 | sigemptyset(&set); |
159 | 0 | ha_sigmask(SIG_SETMASK, &set, NULL); |
160 | 0 | } |
161 | | |
162 | | /* releases all registered signal handlers */ |
163 | | void deinit_signals() |
164 | 0 | { |
165 | 0 | int sig; |
166 | 0 | struct sig_handler *sh, *shb; |
167 | |
|
168 | 0 | for (sig = 0; sig < MAX_SIGNAL; sig++) { |
169 | 0 | if (sig != SIGPROF) |
170 | 0 | signal(sig, SIG_DFL); |
171 | 0 | list_for_each_entry_safe(sh, shb, &signal_state[sig].handlers, list) { |
172 | 0 | LIST_DELETE(&sh->list); |
173 | 0 | pool_free(pool_head_sig_handlers, sh); |
174 | 0 | } |
175 | 0 | } |
176 | 0 | } |
177 | | |
178 | | /* Register a function and an integer argument on a signal. A pointer to the |
179 | | * newly allocated sig_handler is returned, or NULL in case of any error. The |
180 | | * caller is responsible for unregistering the function when not used anymore. |
181 | | * Note that passing a NULL as the function pointer enables interception of the |
182 | | * signal without processing, which is identical to SIG_IGN. If the signal is |
183 | | * zero (which the system cannot deliver), only internal functions will be able |
184 | | * to notify the registered functions. |
185 | | */ |
186 | | struct sig_handler *signal_register_fct(int sig, void (*fct)(struct sig_handler *), int arg) |
187 | 0 | { |
188 | 0 | struct sig_handler *sh; |
189 | |
|
190 | 0 | if (sig < 0 || sig >= MAX_SIGNAL) |
191 | 0 | return NULL; |
192 | | |
193 | 0 | if (sig) |
194 | 0 | signal(sig, fct ? signal_handler : SIG_IGN); |
195 | |
|
196 | 0 | if (!fct) |
197 | 0 | return NULL; |
198 | | |
199 | 0 | sh = pool_alloc(pool_head_sig_handlers); |
200 | 0 | if (!sh) |
201 | 0 | return NULL; |
202 | | |
203 | 0 | sh->handler = fct; |
204 | 0 | sh->arg = arg; |
205 | 0 | sh->flags = SIG_F_TYPE_FCT; |
206 | 0 | LIST_APPEND(&signal_state[sig].handlers, &sh->list); |
207 | 0 | return sh; |
208 | 0 | } |
209 | | |
210 | | /* Register a task and a wake-up reason on a signal. A pointer to the newly |
211 | | * allocated sig_handler is returned, or NULL in case of any error. The caller |
212 | | * is responsible for unregistering the task when not used anymore. Note that |
213 | | * passing a NULL as the task pointer enables interception of the signal |
214 | | * without processing, which is identical to SIG_IGN. If the signal is zero |
215 | | * (which the system cannot deliver), only internal functions will be able to |
216 | | * notify the registered functions. |
217 | | */ |
218 | | struct sig_handler *signal_register_task(int sig, struct task *task, int reason) |
219 | 0 | { |
220 | 0 | struct sig_handler *sh; |
221 | |
|
222 | 0 | if (sig < 0 || sig >= MAX_SIGNAL) |
223 | 0 | return NULL; |
224 | | |
225 | 0 | if (sig) |
226 | 0 | signal(sig, signal_handler); |
227 | |
|
228 | 0 | if (!task) |
229 | 0 | return NULL; |
230 | | |
231 | 0 | sh = pool_alloc(pool_head_sig_handlers); |
232 | 0 | if (!sh) |
233 | 0 | return NULL; |
234 | | |
235 | 0 | sh->handler = task; |
236 | 0 | sh->arg = reason & ~TASK_WOKEN_ANY; |
237 | 0 | sh->flags = SIG_F_TYPE_TASK; |
238 | 0 | LIST_APPEND(&signal_state[sig].handlers, &sh->list); |
239 | 0 | return sh; |
240 | 0 | } |
241 | | |
242 | | /* Immediately unregister a handler so that no further signals may be delivered |
243 | | * to it. The struct is released so the caller may not reference it anymore. |
244 | | */ |
245 | | void signal_unregister_handler(struct sig_handler *handler) |
246 | 0 | { |
247 | 0 | LIST_DELETE(&handler->list); |
248 | 0 | pool_free(pool_head_sig_handlers, handler); |
249 | 0 | } |
250 | | |
251 | | /* Immediately unregister a handler so that no further signals may be delivered |
252 | | * to it. The handler struct does not need to be known, only the function or |
253 | | * task pointer. This method is expensive because it scans all the list, so it |
254 | | * should only be used for rare cases (eg: exit). The struct is released so the |
255 | | * caller may not reference it anymore. |
256 | | */ |
257 | | void signal_unregister_target(int sig, void *target) |
258 | 0 | { |
259 | 0 | struct sig_handler *sh, *shb; |
260 | |
|
261 | 0 | if (sig < 0 || sig >= MAX_SIGNAL) |
262 | 0 | return; |
263 | | |
264 | 0 | if (!target) |
265 | 0 | return; |
266 | | |
267 | 0 | list_for_each_entry_safe(sh, shb, &signal_state[sig].handlers, list) { |
268 | 0 | if (sh->handler == target) { |
269 | 0 | LIST_DELETE(&sh->list); |
270 | 0 | pool_free(pool_head_sig_handlers, sh); |
271 | 0 | break; |
272 | 0 | } |
273 | 0 | } |
274 | 0 | } |
275 | | |
276 | | /* |
277 | | * Immedialtely unregister every handler assigned to a signal <sig>. |
278 | | * Once the handler list is empty, the signal is ignored with SIG_IGN. |
279 | | */ |
280 | | |
281 | | void signal_unregister(int sig) |
282 | 0 | { |
283 | 0 | struct sig_handler *sh, *shb; |
284 | |
|
285 | 0 | if (sig < 0 || sig >= MAX_SIGNAL) |
286 | 0 | return; |
287 | | |
288 | 0 | list_for_each_entry_safe(sh, shb, &signal_state[sig].handlers, list) { |
289 | 0 | LIST_DELETE(&sh->list); |
290 | 0 | pool_free(pool_head_sig_handlers, sh); |
291 | 0 | } |
292 | |
|
293 | | signal(sig, SIG_IGN); |
294 | 0 | } |
295 | | |
296 | | INITCALL0(STG_PREPARE, signal_init); |