Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License");
5 : : * you may not use this file except in compliance with the License.
6 : : * You may obtain a copy of the License at:
7 : : *
8 : : * http://www.apache.org/licenses/LICENSE-2.0
9 : : *
10 : : * Unless required by applicable law or agreed to in writing, software
11 : : * distributed under the License is distributed on an "AS IS" BASIS,
12 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : : * See the License for the specific language governing permissions and
14 : : * limitations under the License.
15 : : */
16 : : #include <config.h>
17 : : #include "fatal-signal.h"
18 : : #include <errno.h>
19 : : #include <signal.h>
20 : : #include <stdbool.h>
21 : : #include <stdio.h>
22 : : #include <stdint.h>
23 : : #include <stdlib.h>
24 : : #include <string.h>
25 : : #include <unistd.h>
26 : : #include "ovs-thread.h"
27 : : #include "poll-loop.h"
28 : : #include "openvswitch/shash.h"
29 : : #include "sset.h"
30 : : #include "signals.h"
31 : : #include "socket-util.h"
32 : : #include "util.h"
33 : : #include "openvswitch/vlog.h"
34 : :
35 : : #include "openvswitch/type-props.h"
36 : :
37 : : #ifndef SIG_ATOMIC_MAX
38 : : #define SIG_ATOMIC_MAX TYPE_MAXIMUM(sig_atomic_t)
39 : : #endif
40 : :
41 : 53956 : VLOG_DEFINE_THIS_MODULE(fatal_signal);
42 : :
43 : : /* Signals to catch. */
44 : : #ifndef _WIN32
45 : : static const int fatal_signals[] = { SIGTERM, SIGINT, SIGHUP, SIGALRM };
46 : : #else
47 : : static const int fatal_signals[] = { SIGTERM };
48 : : #endif
49 : :
50 : : /* Hooks to call upon catching a signal */
51 : : struct hook {
52 : : void (*hook_cb)(void *aux);
53 : : void (*cancel_cb)(void *aux);
54 : : void *aux;
55 : : bool run_at_exit;
56 : : };
57 : : #define MAX_HOOKS 32
58 : : static struct hook hooks[MAX_HOOKS];
59 : : static size_t n_hooks;
60 : :
61 : : static int signal_fds[2];
62 : : static volatile sig_atomic_t stored_sig_nr = SIG_ATOMIC_MAX;
63 : :
64 : : #ifdef _WIN32
65 : : static HANDLE wevent;
66 : : #endif
67 : :
68 : : static struct ovs_mutex mutex;
69 : :
70 : : static void call_hooks(int sig_nr);
71 : : #ifdef _WIN32
72 : : static BOOL WINAPI ConsoleHandlerRoutine(DWORD dwCtrlType);
73 : : #endif
74 : :
75 : : /* Initializes the fatal signal handling module. Calling this function is
76 : : * optional, because calling any other function in the module will also
77 : : * initialize it. However, in a multithreaded program, the module must be
78 : : * initialized while the process is still single-threaded. */
79 : : void
80 : 815238 : fatal_signal_init(void)
81 : : {
82 : : static bool inited = false;
83 : :
84 [ + + ]: 815238 : if (!inited) {
85 : : size_t i;
86 : :
87 : 23626 : assert_single_threaded();
88 : 23626 : inited = true;
89 : :
90 : 23626 : ovs_mutex_init_recursive(&mutex);
91 : : #ifndef _WIN32
92 : 23626 : xpipe_nonblocking(signal_fds);
93 : : #else
94 : : wevent = CreateEvent(NULL, TRUE, FALSE, NULL);
95 : : if (!wevent) {
96 : : char *msg_buf = ovs_lasterror_to_string();
97 : : VLOG_FATAL("Failed to create a event (%s).", msg_buf);
98 : : }
99 : :
100 : : /* Register a function to handle Ctrl+C. */
101 : : SetConsoleCtrlHandler(ConsoleHandlerRoutine, true);
102 : : #endif
103 : :
104 [ + + ]: 118130 : for (i = 0; i < ARRAY_SIZE(fatal_signals); i++) {
105 : 94504 : int sig_nr = fatal_signals[i];
106 : : #ifndef _WIN32
107 : : struct sigaction old_sa;
108 : :
109 : 94504 : xsigaction(sig_nr, NULL, &old_sa);
110 [ + + ]: 94504 : if (old_sa.sa_handler == SIG_DFL
111 [ - + ]: 94501 : && signal(sig_nr, fatal_signal_handler) == SIG_ERR) {
112 : 0 : VLOG_FATAL("signal failed (%s)", ovs_strerror(errno));
113 : : }
114 : : #else
115 : : if (signal(sig_nr, fatal_signal_handler) == SIG_ERR) {
116 : : VLOG_FATAL("signal failed (%s)", ovs_strerror(errno));
117 : : }
118 : : #endif
119 : : }
120 : 23626 : atexit(fatal_signal_atexit_handler);
121 : : }
122 : 815238 : }
123 : :
124 : : /* Registers 'hook_cb' to be called from inside poll_block() following a fatal
125 : : * signal. 'hook_cb' does not need to be async-signal-safe. In a
126 : : * multithreaded program 'hook_cb' might be called from any thread, with
127 : : * threads other than the one running 'hook_cb' in unknown states.
128 : : *
129 : : * If 'run_at_exit' is true, 'hook_cb' is also called during normal process
130 : : * termination, e.g. when exit() is called or when main() returns.
131 : : *
132 : : * If the current process forks, fatal_signal_fork() may be called to clear the
133 : : * parent process's fatal signal hooks, so that 'hook_cb' is only called when
134 : : * the child terminates, not when the parent does. When fatal_signal_fork() is
135 : : * called, it calls the 'cancel_cb' function if it is nonnull, passing 'aux',
136 : : * to notify that the hook has been canceled. This allows the hook to free
137 : : * memory, etc. */
138 : : void
139 : 19354 : fatal_signal_add_hook(void (*hook_cb)(void *aux), void (*cancel_cb)(void *aux),
140 : : void *aux, bool run_at_exit)
141 : : {
142 : 19354 : fatal_signal_init();
143 : :
144 : 19354 : ovs_mutex_lock(&mutex);
145 [ - + ]: 19354 : ovs_assert(n_hooks < MAX_HOOKS);
146 : 19354 : hooks[n_hooks].hook_cb = hook_cb;
147 : 19354 : hooks[n_hooks].cancel_cb = cancel_cb;
148 : 19354 : hooks[n_hooks].aux = aux;
149 : 19354 : hooks[n_hooks].run_at_exit = run_at_exit;
150 : 19354 : n_hooks++;
151 : 19354 : ovs_mutex_unlock(&mutex);
152 : 19354 : }
153 : :
154 : : /* Handles fatal signal number 'sig_nr'.
155 : : *
156 : : * Ordinarily this is the actual signal handler. When other code needs to
157 : : * handle one of our signals, however, it can register for that signal and, if
158 : : * and when necessary, call this function to do fatal signal processing for it
159 : : * and terminate the process. Currently only timeval.c does this, for SIGALRM.
160 : : * (It is not important whether the other code sets up its signal handler
161 : : * before or after this file, because this file will only set up a signal
162 : : * handler in the case where the signal has its default handling.) */
163 : : void
164 : 0 : fatal_signal_handler(int sig_nr)
165 : : {
166 : : #ifndef _WIN32
167 : 0 : ignore(write(signal_fds[1], "", 1));
168 : : #else
169 : : SetEvent(wevent);
170 : : #endif
171 : 0 : stored_sig_nr = sig_nr;
172 : 0 : }
173 : :
174 : : /* Check whether a fatal signal has occurred and, if so, call the fatal signal
175 : : * hooks and exit.
176 : : *
177 : : * This function is called automatically by poll_block(), but specialized
178 : : * programs that may not always call poll_block() on a regular basis should
179 : : * also call it periodically. (Therefore, any function with "block" in its
180 : : * name should call fatal_signal_run() each time it is called, either directly
181 : : * or through poll_block(), because such functions can only used by specialized
182 : : * programs that can afford to block outside their main loop around
183 : : * poll_block().)
184 : : */
185 : : void
186 : 430363 : fatal_signal_run(void)
187 : : {
188 : : sig_atomic_t sig_nr;
189 : :
190 : 430363 : fatal_signal_init();
191 : :
192 : 430361 : sig_nr = stored_sig_nr;
193 [ - + ]: 430361 : if (sig_nr != SIG_ATOMIC_MAX) {
194 : : char namebuf[SIGNAL_NAME_BUFSIZE];
195 : :
196 : 0 : ovs_mutex_lock(&mutex);
197 : :
198 : : #ifndef _WIN32
199 [ # # ]: 0 : VLOG_WARN("terminating with signal %d (%s)",
200 : : (int)sig_nr, signal_name(sig_nr, namebuf, sizeof namebuf));
201 : : #else
202 : : VLOG_WARN("terminating with signal %d", (int)sig_nr);
203 : : #endif
204 : 0 : call_hooks(sig_nr);
205 : 0 : fflush(stderr);
206 : :
207 : : /* Re-raise the signal with the default handling so that the program
208 : : * termination status reflects that we were killed by this signal */
209 : 0 : signal(sig_nr, SIG_DFL);
210 : 0 : raise(sig_nr);
211 : :
212 : 0 : ovs_mutex_unlock(&mutex);
213 : 0 : OVS_NOT_REACHED();
214 : : }
215 : 430361 : }
216 : :
217 : : void
218 : 344803 : fatal_signal_wait(void)
219 : : {
220 : 344803 : fatal_signal_init();
221 : : #ifdef _WIN32
222 : : poll_wevent_wait(wevent);
223 : : #else
224 : 344802 : poll_fd_wait(signal_fds[0], POLLIN);
225 : : #endif
226 : 344803 : }
227 : :
228 : : void
229 : 15097 : fatal_ignore_sigpipe(void)
230 : : {
231 : : #ifndef _WIN32
232 : 15097 : signal(SIGPIPE, SIG_IGN);
233 : : #endif
234 : 15097 : }
235 : :
236 : : void
237 : 24341 : fatal_signal_atexit_handler(void)
238 : : {
239 : 24341 : call_hooks(0);
240 : 24341 : }
241 : :
242 : : static void
243 : 24341 : call_hooks(int sig_nr)
244 : : {
245 : : static volatile sig_atomic_t recurse = 0;
246 [ + - ]: 24341 : if (!recurse) {
247 : : size_t i;
248 : :
249 : 24341 : recurse = 1;
250 : :
251 [ + + ]: 43667 : for (i = 0; i < n_hooks; i++) {
252 : 19326 : struct hook *h = &hooks[i];
253 [ + - ][ + - ]: 19326 : if (sig_nr || h->run_at_exit) {
254 : 19326 : h->hook_cb(h->aux);
255 : : }
256 : : }
257 : : }
258 : 24341 : }
259 : :
260 : : #ifdef _WIN32
261 : : BOOL WINAPI ConsoleHandlerRoutine(DWORD dwCtrlType)
262 : : {
263 : : stored_sig_nr = SIGINT;
264 : : SetEvent(wevent);
265 : : return true;
266 : : }
267 : : #endif
268 : :
269 : : /* Files to delete on exit. */
270 : : static struct sset files = SSET_INITIALIZER(&files);
271 : :
272 : : /* Has a hook function been registered with fatal_signal_add_hook() (and not
273 : : * cleared by fatal_signal_fork())? */
274 : : static bool added_hook;
275 : :
276 : : static void unlink_files(void *aux);
277 : : static void cancel_files(void *aux);
278 : : static void do_unlink_files(void);
279 : :
280 : : /* Registers 'file' to be unlinked when the program terminates via exit() or a
281 : : * fatal signal. */
282 : : void
283 : 9050 : fatal_signal_add_file_to_unlink(const char *file)
284 : : {
285 : 9050 : fatal_signal_init();
286 : :
287 : 9050 : ovs_mutex_lock(&mutex);
288 [ + + ]: 9050 : if (!added_hook) {
289 : 2191 : added_hook = true;
290 : 2191 : fatal_signal_add_hook(unlink_files, cancel_files, NULL, true);
291 : : }
292 : :
293 : 9050 : sset_add(&files, file);
294 : 9050 : ovs_mutex_unlock(&mutex);
295 : 9050 : }
296 : :
297 : : /* Unregisters 'file' from being unlinked when the program terminates via
298 : : * exit() or a fatal signal. */
299 : : void
300 : 6868 : fatal_signal_remove_file_to_unlink(const char *file)
301 : : {
302 : 6868 : fatal_signal_init();
303 : :
304 : 6868 : ovs_mutex_lock(&mutex);
305 : 6868 : sset_find_and_delete(&files, file);
306 : 6868 : ovs_mutex_unlock(&mutex);
307 : 6868 : }
308 : :
309 : : /* Like fatal_signal_remove_file_to_unlink(), but also unlinks 'file'.
310 : : * Returns 0 if successful, otherwise a positive errno value. */
311 : : int
312 : 4801 : fatal_signal_unlink_file_now(const char *file)
313 : : {
314 : : int error;
315 : :
316 : 4801 : fatal_signal_init();
317 : :
318 : 4801 : ovs_mutex_lock(&mutex);
319 : :
320 [ + + ]: 4801 : error = unlink(file) ? errno : 0;
321 [ + + ]: 4801 : if (error) {
322 [ + - ]: 2 : VLOG_WARN("could not unlink \"%s\" (%s)", file, ovs_strerror(error));
323 : : }
324 : :
325 : 4801 : fatal_signal_remove_file_to_unlink(file);
326 : :
327 : 4801 : ovs_mutex_unlock(&mutex);
328 : :
329 : 4801 : return error;
330 : : }
331 : :
332 : : static void
333 : 2189 : unlink_files(void *aux OVS_UNUSED)
334 : : {
335 : 2189 : do_unlink_files();
336 : 2189 : }
337 : :
338 : : static void
339 : 111 : cancel_files(void *aux OVS_UNUSED)
340 : : {
341 : 111 : sset_clear(&files);
342 : 111 : added_hook = false;
343 : 111 : }
344 : :
345 : : static void
346 : 2189 : do_unlink_files(void)
347 : : {
348 : : const char *file;
349 : :
350 [ + + ][ + + ]: 4369 : SSET_FOR_EACH (file, &files) {
[ + + ]
351 : 2180 : unlink(file);
352 : : }
353 : 2189 : }
354 : :
355 : : /* Clears all of the fatal signal hooks without executing them. If any of the
356 : : * hooks passed a 'cancel_cb' function to fatal_signal_add_hook(), then those
357 : : * functions will be called, allowing them to free resources, etc.
358 : : *
359 : : * Following a fork, one of the resulting processes can call this function to
360 : : * allow it to terminate without calling the hooks registered before calling
361 : : * this function. New hooks registered after calling this function will take
362 : : * effect normally. */
363 : : void
364 : 2257 : fatal_signal_fork(void)
365 : : {
366 : : size_t i;
367 : :
368 : 2257 : assert_single_threaded();
369 : :
370 [ + + ]: 3077 : for (i = 0; i < n_hooks; i++) {
371 : 820 : struct hook *h = &hooks[i];
372 [ + + ]: 820 : if (h->cancel_cb) {
373 : 111 : h->cancel_cb(h->aux);
374 : : }
375 : : }
376 : 2257 : n_hooks = 0;
377 : :
378 : : /* Raise any signals that we have already received with the default
379 : : * handler. */
380 [ - + ]: 2257 : if (stored_sig_nr != SIG_ATOMIC_MAX) {
381 : 0 : raise(stored_sig_nr);
382 : : }
383 : 2257 : }
384 : :
385 : : #ifndef _WIN32
386 : : /* Blocks all fatal signals and returns previous signal mask into
387 : : * 'prev_mask'. */
388 : : void
389 : 108 : fatal_signal_block(sigset_t *prev_mask)
390 : : {
391 : : int i;
392 : : sigset_t block_mask;
393 : :
394 : 108 : sigemptyset(&block_mask);
395 [ + + ]: 540 : for (i = 0; i < ARRAY_SIZE(fatal_signals); i++) {
396 : 432 : int sig_nr = fatal_signals[i];
397 : 432 : sigaddset(&block_mask, sig_nr);
398 : : }
399 : 108 : xpthread_sigmask(SIG_BLOCK, &block_mask, prev_mask);
400 : 108 : }
401 : : #endif
|