X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Ffatal-signal.c;h=35a37bff649f4756e6507681bcaa5eb1be902958;hb=21e087cf0dff612754649f43fdf9715f701cae7a;hp=5ab62848659ceed9777b4514d06e16faaf3b9ff5;hpb=468e00132f76a6d057da1520873e7a468ccae422;p=sliver-openvswitch.git diff --git a/lib/fatal-signal.c b/lib/fatal-signal.c index 5ab628486..35a37bff6 100644 --- a/lib/fatal-signal.c +++ b/lib/fatal-signal.c @@ -1,3 +1,36 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ +#include #include "fatal-signal.h" #include #include @@ -10,7 +43,7 @@ #include "util.h" /* Signals to catch. */ -static const int fatal_signals[] = { SIGTERM, SIGINT, SIGHUP }; +static const int fatal_signals[] = { SIGTERM, SIGINT, SIGHUP, SIGALRM }; /* Signals to catch as a sigset_t. */ static sigset_t fatal_signal_set; @@ -19,6 +52,7 @@ static sigset_t fatal_signal_set; struct hook { void (*func)(void *aux); void *aux; + bool run_at_exit; }; #define MAX_HOOKS 32 static struct hook hooks[MAX_HOOKS]; @@ -30,18 +64,24 @@ static int block_level = 0; /* Signal mask saved by outermost signal blocker. */ static sigset_t saved_signal_mask; +/* Disabled by fatal_signal_fork()? */ +static bool disabled; + static void call_sigprocmask(int how, sigset_t* new_set, sigset_t* old_set); -static void signal_handler(int sig_nr); +static void atexit_handler(void); +static void call_hooks(int sig_nr); -/* Registers 'hook' to be called when a process termination signal is - * raised. */ +/* Registers 'hook' to be called when a process termination signal is raised. + * If 'run_at_exit' is true, 'hook' is also called during normal process + * termination, e.g. when exit() is called or when main() returns. */ void -fatal_signal_add_hook(void (*func)(void *aux), void *aux) +fatal_signal_add_hook(void (*func)(void *aux), void *aux, bool run_at_exit) { fatal_signal_block(); assert(n_hooks < MAX_HOOKS); hooks[n_hooks].func = func; hooks[n_hooks].aux = aux; + hooks[n_hooks].run_at_exit = run_at_exit; n_hooks++; fatal_signal_unblock(); } @@ -64,11 +104,18 @@ fatal_signal_block() sigemptyset(&fatal_signal_set); for (i = 0; i < ARRAY_SIZE(fatal_signals); i++) { int sig_nr = fatal_signals[i]; + struct sigaction old_sa; + sigaddset(&fatal_signal_set, sig_nr); - if (signal(sig_nr, signal_handler) == SIG_IGN) { - signal(sig_nr, SIG_IGN); + if (sigaction(sig_nr, NULL, &old_sa)) { + ofp_fatal(errno, "sigaction"); + } + if (old_sa.sa_handler == SIG_DFL + && signal(sig_nr, fatal_signal_handler) == SIG_ERR) { + ofp_fatal(errno, "signal"); } } + atexit(atexit_handler); } if (++block_level == 1) { @@ -88,6 +135,52 @@ fatal_signal_unblock() call_sigprocmask(SIG_SETMASK, &saved_signal_mask, NULL); } } + +/* Handles fatal signal number 'sig_nr'. + * + * Ordinarily this is the actual signal handler. When other code needs to + * handle one of our signals, however, it can register for that signal and, if + * and when necessary, call this function to do fatal signal processing for it + * and terminate the process. Currently only timeval.c does this, for SIGALRM. + * (It is not important whether the other code sets up its signal handler + * before or after this file, because this file will only set up a signal + * handler in the case where the signal has its default handling.) */ +void +fatal_signal_handler(int sig_nr) +{ + call_hooks(sig_nr); + + /* Re-raise the signal with the default handling so that the program + * termination status reflects that we were killed by this signal */ + signal(sig_nr, SIG_DFL); + raise(sig_nr); +} + +static void +atexit_handler(void) +{ + if (!disabled) { + call_hooks(0); + } +} + +static void +call_hooks(int sig_nr) +{ + static volatile sig_atomic_t recurse = 0; + if (!recurse) { + size_t i; + + recurse = 1; + + for (i = 0; i < n_hooks; i++) { + struct hook *h = &hooks[i]; + if (sig_nr || h->run_at_exit) { + h->func(h->aux); + } + } + } +} static char **files; static size_t n_files, max_files; @@ -103,8 +196,7 @@ fatal_signal_add_file_to_unlink(const char *file) static bool added_hook = false; if (!added_hook) { added_hook = true; - fatal_signal_add_hook(unlink_files, NULL); - atexit(do_unlink_files); + fatal_signal_add_hook(unlink_files, NULL, true); } fatal_signal_block(); @@ -137,7 +229,7 @@ fatal_signal_remove_file_to_unlink(const char *file) static void unlink_files(void *aux UNUSED) { - do_unlink_files(); + do_unlink_files(); } static void @@ -150,6 +242,25 @@ do_unlink_files(void) } } +/* Disables the fatal signal hook mechanism. Following a fork, one of the + * resulting processes can call this function to allow it to terminate without + * triggering fatal signal processing or removing files. Fatal signal + * processing is still enabled in the other process. */ +void +fatal_signal_fork(void) +{ + size_t i; + + disabled = true; + + for (i = 0; i < ARRAY_SIZE(fatal_signals); i++) { + int sig_nr = fatal_signals[i]; + if (signal(sig_nr, SIG_DFL) == SIG_IGN) { + signal(sig_nr, SIG_IGN); + } + } +} + static void call_sigprocmask(int how, sigset_t* new_set, sigset_t* old_set) { @@ -158,24 +269,3 @@ call_sigprocmask(int how, sigset_t* new_set, sigset_t* old_set) fprintf(stderr, "sigprocmask: %s\n", strerror(errno)); } } - -static void -signal_handler(int sig_nr) -{ - volatile sig_atomic_t recurse = 0; - if (!recurse) { - size_t i; - - recurse = 1; - - /* Call all the hooks. */ - for (i = 0; i < n_hooks; i++) { - hooks[i].func(hooks[i].aux); - } - } - - /* Re-raise the signal with the default handling so that the program - * termination status reflects that we were killed by this signal */ - signal(sig_nr, SIG_DFL); - raise(sig_nr); -}