X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Ffatal-signal.c;h=9a6f5f1a326870d5c1ee6fe3b5f840d54bb9be8d;hb=1276a2c5f24c0c932426aca9c899fa524d2443f2;hp=8718fd606deb0698bcd93b6ee67baab041a6f1d4;hpb=2220ef77b370b8a55591463e49d2789464f38aa5;p=gnulib.git diff --git a/lib/fatal-signal.c b/lib/fatal-signal.c index 8718fd606..9a6f5f1a3 100644 --- a/lib/fatal-signal.c +++ b/lib/fatal-signal.c @@ -1,11 +1,11 @@ /* Emergency actions in case of a fatal signal. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003-2004, 2006-2014 Free Software Foundation, Inc. Written by Bruno Haible , 2003. - This program is free software; you can redistribute it and/or modify + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,13 +13,10 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + along with this program. If not, see . */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif +#include /* Specification. */ #include "fatal-signal.h" @@ -27,16 +24,13 @@ #include #include #include -#include -#if HAVE_UNISTD_H -# include -#endif +#include +#include "sig-handler.h" #include "xalloc.h" #define SIZEOF(a) (sizeof(a) / sizeof(a[0])) - /* ========================================================================= */ @@ -54,7 +48,7 @@ plus SIGXCPU, SIGXFSZ - because they are quite similar to SIGTERM. */ -static const int fatal_signals[] = +static int fatal_signals[] = { /* ISO C 99 signals. */ #ifdef SIGINT @@ -77,11 +71,38 @@ static const int fatal_signals[] = #ifdef SIGXFSZ SIGXFSZ, #endif + /* Native Windows signals. */ +#ifdef SIGBREAK + SIGBREAK, +#endif 0 }; #define num_fatal_signals (SIZEOF (fatal_signals) - 1) +/* Eliminate signals whose signal handler is SIG_IGN. */ + +static void +init_fatal_signals (void) +{ + static bool fatal_signals_initialized = false; + if (!fatal_signals_initialized) + { + size_t i; + + for (i = 0; i < num_fatal_signals; i++) + { + struct sigaction action; + + if (sigaction (fatal_signals[i], NULL, &action) >= 0 + && get_handler (&action) == SIG_IGN) + fatal_signals[i] = -1; + } + + fatal_signals_initialized = true; + } +} + /* ========================================================================= */ @@ -104,14 +125,25 @@ static sig_atomic_t volatile actions_count = 0; static size_t actions_allocated = SIZEOF (static_actions); +/* The saved signal handlers. + Size 32 would not be sufficient: On HP-UX, SIGXCPU = 33, SIGXFSZ = 34. */ +static struct sigaction saved_sigactions[64]; + + /* Uninstall the handlers. */ -static inline void -uninstall_handlers () +static void +uninstall_handlers (void) { size_t i; for (i = 0; i < num_fatal_signals; i++) - signal (fatal_signals[i], SIG_DFL); + if (fatal_signals[i] >= 0) + { + int sig = fatal_signals[i]; + if (saved_sigactions[sig].sa_handler == SIG_IGN) + saved_sigactions[sig].sa_handler = SIG_DFL; + sigaction (sig, &saved_sigactions[sig], NULL); + } } @@ -125,7 +157,7 @@ fatal_signal_handler (int sig) action_t action; size_t n = actions_count; if (n == 0) - break; + break; n--; actions_count = n; action = actions[n].action; @@ -134,26 +166,37 @@ fatal_signal_handler (int sig) } /* Now execute the signal's default action. - If signal() blocks the signal being delivered for the duration of the - signal handler's execution, the re-raised signal is delivered when this - handler returns; otherwise it is delivered already during raise(). */ + If the signal being delivered was blocked, the re-raised signal would be + delivered when this handler returns. But the way we install this handler, + no signal is blocked, and the re-raised signal is delivered already + during raise(). */ uninstall_handlers (); -#if HAVE_RAISE raise (sig); -#else - kill (getpid (), sig); -#endif } /* Install the handlers. */ -static inline void -install_handlers () +static void +install_handlers (void) { size_t i; - + struct sigaction action; + + action.sa_handler = &fatal_signal_handler; + /* If we get a fatal signal while executing fatal_signal_handler, enter + fatal_signal_handler recursively, since it is reentrant. Hence no + SA_RESETHAND. */ + action.sa_flags = SA_NODEFER; + sigemptyset (&action.sa_mask); for (i = 0; i < num_fatal_signals; i++) - signal (fatal_signals[i], &fatal_signal_handler); + if (fatal_signals[i] >= 0) + { + int sig = fatal_signals[i]; + + if (!(sig < sizeof (saved_sigactions) / sizeof (saved_sigactions[0]))) + abort (); + sigaction (sig, &action, &saved_sigactions[sig]); + } } @@ -165,6 +208,7 @@ at_fatal_signal (action_t action) static bool cleanup_initialized = false; if (!cleanup_initialized) { + init_fatal_signals (); install_handlers (); cleanup_initialized = true; } @@ -172,20 +216,25 @@ at_fatal_signal (action_t action) if (actions_count == actions_allocated) { /* Extend the actions array. Note that we cannot use xrealloc(), - because then the cleanup() function could access an already - deallocated array. */ + because then the cleanup() function could access an already + deallocated array. */ actions_entry_t *old_actions = actions; + size_t old_actions_allocated = actions_allocated; size_t new_actions_allocated = 2 * actions_allocated; actions_entry_t *new_actions = - xmalloc (new_actions_allocated * sizeof (actions_entry_t)); - - memcpy (new_actions, old_actions, - actions_allocated * sizeof (actions_entry_t)); + XNMALLOC (new_actions_allocated, actions_entry_t); + size_t k; + + /* Don't use memcpy() here, because memcpy takes non-volatile arguments + and is therefore not guaranteed to complete all memory stores before + the next statement. */ + for (k = 0; k < old_actions_allocated; k++) + new_actions[k] = old_actions[k]; actions = new_actions; actions_allocated = new_actions_allocated; /* Now we can free the old actions array. */ if (old_actions != static_actions) - free (old_actions); + free (old_actions); } /* The two uses of 'volatile' in the types above (and ISO C 99 section 5.1.2.3.(5)) ensure that we increment the actions_count only after @@ -199,21 +248,22 @@ at_fatal_signal (action_t action) /* ========================================================================= */ -#if HAVE_POSIX_SIGNALBLOCKING - static sigset_t fatal_signal_set; static void -init_fatal_signal_set () +init_fatal_signal_set (void) { static bool fatal_signal_set_initialized = false; if (!fatal_signal_set_initialized) { size_t i; + init_fatal_signals (); + sigemptyset (&fatal_signal_set); for (i = 0; i < num_fatal_signals; i++) - sigaddset (&fatal_signal_set, fatal_signals[i]); + if (fatal_signals[i] >= 0) + sigaddset (&fatal_signal_set, fatal_signals[i]); fatal_signal_set_initialized = true; } @@ -221,7 +271,7 @@ init_fatal_signal_set () /* Temporarily delay the catchable fatal signals. */ void -block_fatal_signals () +block_fatal_signals (void) { init_fatal_signal_set (); sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL); @@ -229,25 +279,8 @@ block_fatal_signals () /* Stop delaying the catchable fatal signals. */ void -unblock_fatal_signals () +unblock_fatal_signals (void) { init_fatal_signal_set (); sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL); } - -#else - -/* Don't bother caring about the old systems which don't have POSIX signal - blocking. */ - -void -block_fatal_signals () -{ -} - -void -unblock_fatal_signals () -{ -} - -#endif