New module 'fatal-signal'.
authorBruno Haible <bruno@clisp.org>
Mon, 6 Oct 2003 12:50:11 +0000 (12:50 +0000)
committerBruno Haible <bruno@clisp.org>
Mon, 6 Oct 2003 12:50:11 +0000 (12:50 +0000)
ChangeLog
MODULES.html.sh
lib/ChangeLog
lib/fatal-signal.c [new file with mode: 0644]
lib/fatal-signal.h [new file with mode: 0644]
m4/ChangeLog
m4/fatal-signal.m4 [new file with mode: 0644]
m4/signalblocking.m4 [new file with mode: 0644]
modules/fatal-signal [new file with mode: 0644]

index d7dfc99cae99b097847887844698e8c1953f065d..d44269dfdc8ccb81e509cfd85fb401449a94515e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2003-10-06  Bruno Haible  <bruno@clisp.org>
+
+       * modules/fatal-signal: New file.
+       * MODULES.html.sh (func_all_modules): Add fatal-signal.
+
 2003-10-05  Paul Eggert  <eggert@twinsun.com>
 
        * README: Rework advice for preventing empty .o files.
@@ -12,8 +17,8 @@
 
 2003-10-01  Simon Josefsson  <jas@extundo.com>
 
-       * 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  <oskar@osk.mine.nu>
 
index cc35a11eb449f5d67c7baeb49c595bdb12c508bd..384ef78ebc9ece5fddc8fe15e406c0595bc936f7 100755 (executable)
@@ -1549,6 +1549,16 @@ func_all_modules ()
   func_module vasprintf
   func_end_table
 
+  element="Signal handling <signal.h>"
+  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
index 83887a2e33703b139e789b8a04df2ca06759935b..8fc63aad66436455c8f5bb1af0b1b122909a9ec3 100644 (file)
@@ -1,3 +1,8 @@
+2003-10-06  Bruno Haible  <bruno@clisp.org>
+
+       * fatal-signal.h: New file, from GNU gettext.
+       * fatal-signal.c: New file, from GNU gettext.
+
 2003-10-04  Karl Berry  <karl@gnu.org>
 
        * argp*: update from libc.
diff --git a/lib/fatal-signal.c b/lib/fatal-signal.c
new file mode 100644 (file)
index 0000000..ea78012
--- /dev/null
@@ -0,0 +1,232 @@
+/* Emergency actions in case of a fatal signal.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 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 <stdbool.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#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 (file)
index 0000000..ffbc4a8
--- /dev/null
@@ -0,0 +1,52 @@
+/* Emergency actions in case of a fatal signal.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 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
index f0893aa2cbd1d2a01732d4a6d75747d88b5f2b25..63e9433382ec9a2bbbc7fc0ff784e019af24aa82 100644 (file)
@@ -1,3 +1,8 @@
+2003-10-06  Bruno Haible  <bruno@clisp.org>
+
+       * fatal-signal.m4: New file.
+       * signalblocking.m4: New file, from GNU gettext.
+
 2003-09-27  Paul Eggert  <eggert@twinsun.com>
 
        * free.m4: New file.
diff --git a/m4/fatal-signal.m4 b/m4/fatal-signal.m4
new file mode 100644 (file)
index 0000000..6d48e3a
--- /dev/null
@@ -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 (file)
index 0000000..1a88f52
--- /dev/null
@@ -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 (file)
index 0000000..e1a0715
--- /dev/null
@@ -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
+