From: Bruno Haible Date: Mon, 6 Oct 2003 12:50:11 +0000 (+0000) Subject: New module 'fatal-signal'. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=40b33d9d6c32cd1afac372a5da2b002aac5a881d;p=pspp New module 'fatal-signal'. --- diff --git a/ChangeLog b/ChangeLog index d7dfc99cae..d44269dfdc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2003-10-06 Bruno Haible + + * modules/fatal-signal: New file. + * MODULES.html.sh (func_all_modules): Add fatal-signal. + 2003-10-05 Paul Eggert * README: Rework advice for preventing empty .o files. @@ -12,8 +17,8 @@ 2003-10-01 Simon Josefsson - * MODULES.html.sh: Move gethostname from section 'based on' to section - 'lacking' POSIX:2001. + * MODULES.html.sh (func_all_modules): Move gethostname from section + 'based on' to section 'lacking' POSIX:2001. 2003-09-27 Oskar Liljeblad diff --git a/MODULES.html.sh b/MODULES.html.sh index cc35a11eb4..384ef78ebc 100755 --- a/MODULES.html.sh +++ b/MODULES.html.sh @@ -1549,6 +1549,16 @@ func_all_modules () func_module vasprintf func_end_table + element="Signal handling " + element=`printf "%s" "$element" | sed -e "$sed_lt" -e "$sed_gt"` + func_section_wrap ansic_ext_signal + func_wrap H3 + func_echo "$element" + + func_begin_table + func_module fatal-signal + func_end_table + element="Command-line arguments" element=`printf "%s" "$element" | sed -e "$sed_lt" -e "$sed_gt"` func_section_wrap ansic_ext_argv diff --git a/lib/ChangeLog b/lib/ChangeLog index 83887a2e33..8fc63aad66 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,8 @@ +2003-10-06 Bruno Haible + + * fatal-signal.h: New file, from GNU gettext. + * fatal-signal.c: New file, from GNU gettext. + 2003-10-04 Karl Berry * argp*: update from libc. diff --git a/lib/fatal-signal.c b/lib/fatal-signal.c new file mode 100644 index 0000000000..ea78012dd9 --- /dev/null +++ b/lib/fatal-signal.c @@ -0,0 +1,232 @@ +/* Emergency actions in case of a fatal signal. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Bruno Haible , 2003. + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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. */ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +/* Specification. */ +#include "fatal-signal.h" + +#include +#include +#include +#include +#if HAVE_UNISTD_H +# include +#endif + +#include "xalloc.h" + +#define SIZEOF(a) (sizeof(a) / sizeof(a[0])) + + +/* ========================================================================= */ + + +/* The list of fatal signals. + These are those signals whose default action is to terminate the process + without a core dump, except + SIGKILL - because it cannot be caught, + SIGALRM SIGUSR1 SIGUSR2 SIGPOLL SIGIO SIGLOST - because applications + often use them for their own purpose, + SIGPROF SIGVTALRM - because they are used for profiling, + SIGSTKFLT - because it is more similar to SIGFPE, SIGSEGV, SIGBUS, + SIGSYS - because it is more similar to SIGABRT, SIGSEGV, + SIGPWR - because it of too special use, + plus + SIGXCPU, SIGXFSZ - because they are quite similar to SIGTERM. */ + +static const int fatal_signals[] = + { + /* ISO C 99 signals. */ +#ifdef SIGINT + SIGINT, +#endif +#ifdef SIGTERM + SIGTERM, +#endif + /* POSIX:2001 signals. */ +#ifdef SIGHUP + SIGHUP, +#endif +#ifdef SIGPIPE + SIGPIPE, +#endif + /* BSD signals. */ +#ifdef SIGXCPU + SIGXCPU, +#endif +#ifdef SIGXFSZ + SIGXFSZ, +#endif + 0 + }; + +#define num_fatal_signals (SIZEOF (fatal_signals) - 1) + + +/* ========================================================================= */ + + +/* The registered cleanup actions. */ +typedef void (*action_t) (void); +static action_t static_actions[32]; +static action_t * volatile actions = static_actions; +static size_t volatile actions_count = 0; +static size_t actions_allocated = SIZEOF (static_actions); + + +/* Uninstall the handlers. */ +static inline void +uninstall_handlers () +{ + size_t i; + + for (i = 0; i < num_fatal_signals; i++) + signal (fatal_signals[i], SIG_DFL); +} + + +/* The signal handler. It gets called asynchronously. */ +static void +fatal_signal_handler (int sig) +{ + for (;;) + { + /* Get the last registered cleanup action, in a reentrant way. */ + action_t action; + size_t n = actions_count; + if (n == 0) + break; + n--; + actions_count = n; + action = actions[n]; + /* Execute the action. */ + action (); + } + + /* Now execute the signal's default action. */ + uninstall_handlers (); +#if HAVE_RAISE + raise (sig); +#else + kill (getpid (), sig); +#endif +} + + +/* Install the handlers. */ +static inline void +install_handlers () +{ + size_t i; + + for (i = 0; i < num_fatal_signals; i++) + signal (fatal_signals[i], &fatal_signal_handler); +} + + +/* Register a cleanup function to be executed when a catchable fatal signal + occurs. */ +void +at_fatal_signal (action_t action) +{ + static bool cleanup_initialized = false; + if (!cleanup_initialized) + { + install_handlers (); + cleanup_initialized = true; + } + + 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. */ + action_t *old_actions = actions; + size_t new_actions_allocated = 2 * actions_allocated; + action_t *new_actions = + xmalloc (new_actions_allocated * sizeof (action_t)); + + memcpy (new_actions, actions, actions_allocated * sizeof (action_t)); + actions = new_actions; + actions_allocated = new_actions_allocated; + /* Now we can free the old actions array. */ + if (old_actions != static_actions) + free (old_actions); + } + actions[actions_count] = action; + actions_count++; +} + + +/* ========================================================================= */ + + +#if HAVE_POSIX_SIGNALBLOCKING + +static sigset_t fatal_signal_set; + +static void +init_fatal_signal_set () +{ + static bool fatal_signal_set_initialized = false; + if (!fatal_signal_set_initialized) + { + size_t i; + + sigemptyset (&fatal_signal_set); + for (i = 0; i < num_fatal_signals; i++) + sigaddset (&fatal_signal_set, fatal_signals[i]); + + fatal_signal_set_initialized = true; + } +} + +void +block_fatal_signals () +{ + init_fatal_signal_set (); + sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL); +} + +void +unblock_fatal_signals () +{ + 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 diff --git a/lib/fatal-signal.h b/lib/fatal-signal.h new file mode 100644 index 0000000000..ffbc4a837d --- /dev/null +++ b/lib/fatal-signal.h @@ -0,0 +1,52 @@ +/* Emergency actions in case of a fatal signal. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Bruno Haible , 2003. + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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. */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* It is often useful to do some cleanup action when a usually fatal signal + terminates the process, like removing a temporary file or killing a + subprocess that may be stuck waiting for a device, pipe or network input. + Such signals are SIGHUP, SIGINT, SIGPIPE, SIGTERM, and possibly others. + The limitation of this facility is that it cannot work for SIGKILL. */ + +/* Register a cleanup function to be executed when a catchable fatal signal + occurs. */ +extern void at_fatal_signal (void (*function) (void)); + + +/* Sometimes it is necessary to block the usually fatal signals while the + data structures being accessed by the cleanup action are being built or + reorganized. This is the case, for example, when a temporary file or + directory is created through mkstemp() or mkdtemp(), because these + functions create the temporary file or directory _before_ returning its + name to the application. */ + +/* Temporarily delay the catchable fatal signals. */ +extern void block_fatal_signals (void); + +/* Stop delaying the catchable fatal signals. */ +extern void unblock_fatal_signals (void); + + +#ifdef __cplusplus +} +#endif diff --git a/m4/ChangeLog b/m4/ChangeLog index f0893aa2cb..63e9433382 100644 --- a/m4/ChangeLog +++ b/m4/ChangeLog @@ -1,3 +1,8 @@ +2003-10-06 Bruno Haible + + * fatal-signal.m4: New file. + * signalblocking.m4: New file, from GNU gettext. + 2003-09-27 Paul Eggert * free.m4: New file. diff --git a/m4/fatal-signal.m4 b/m4/fatal-signal.m4 new file mode 100644 index 0000000000..6d48e3a71b --- /dev/null +++ b/m4/fatal-signal.m4 @@ -0,0 +1,14 @@ +# fatal-signal.m4 serial 1 +dnl Copyright (C) 2003 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +AC_DEFUN([gl_FATAL_SIGNAL], +[ + AC_REQUIRE([gt_SIGNALBLOCKING]) + AC_CHECK_HEADERS_ONCE(unistd.h) + AC_CHECK_FUNCS(raise) +]) diff --git a/m4/signalblocking.m4 b/m4/signalblocking.m4 new file mode 100644 index 0000000000..1a88f52fd6 --- /dev/null +++ b/m4/signalblocking.m4 @@ -0,0 +1,23 @@ +# signalblocking.m4 serial 1 (gettext-0.11) +dnl Copyright (C) 2001-2002 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +# Determine available signal blocking primitives. Three different APIs exist: +# 1) POSIX: sigemptyset, sigaddset, sigprocmask +# 2) SYSV: sighold, sigrelse +# 3) BSD: sigblock, sigsetmask +# For simplicity, here we check only for the POSIX signal blocking. +AC_DEFUN([gt_SIGNALBLOCKING], +[ + signals_not_posix= + AC_EGREP_HEADER(sigset_t, signal.h, , signals_not_posix=1) + if test -z "$signals_not_posix"; then + AC_CHECK_FUNC(sigprocmask, + AC_DEFINE(HAVE_POSIX_SIGNALBLOCKING, 1, + [Define to 1 if you have the sigset_t type and the sigprocmask function.])) + fi +]) diff --git a/modules/fatal-signal b/modules/fatal-signal new file mode 100644 index 0000000000..e1a0715e33 --- /dev/null +++ b/modules/fatal-signal @@ -0,0 +1,25 @@ +Description: +Emergency actions in case of a fatal signal. + +Files: +lib/fatal-signal.h +lib/fatal-signal.c +m4/fatal-signal.m4 +m4/signalblocking.m4 + +Depends-on: +xalloc +stdbool + +configure.ac: +gl_FATAL_SIGNAL + +Makefile.am: +lib_SOURCES += fatal-signal.h fatal-signal.c + +Include: +"fatal-signal.h" + +Maintainer: +Bruno Haible +