changeset 10229:29502a2dd08a

New module sigaction, for mingw. * modules/sigaction: New module... * modules/sigaction-tests: ...and its test. * m4/sigaction.m4: New file. * lib/sigaction.c: Likewise. * tests/test-sigaction.c: Likewise. * m4/signal_h.m4 (gl_SIGNAL_H_DEFAULTS): Add sigaction variables. * modules/signal (Makefile.am): Likewise. * lib/signal.in.h (!@HAVE_SIGACTION@): Define replacements when needed. * doc/posix-headers/signal.texi (signal.h): Mention provided types. * doc/posix-functions/siginterrupt.texi (siginterrupt): Mention that sigaction is preferable. * doc/posix-functions/sigaction.texi (sigaction): Mention new module. * MODULES.html.sh (Support for systems lacking POSIX:2001): Add sigaction. Signed-off-by: Eric Blake <ebb9@byu.net>
author Eric Blake <ebb9@byu.net>
date Sat, 21 Jun 2008 14:32:55 -0600
parents 9b123d1aa781
children 54813304edd2
files ChangeLog MODULES.html.sh doc/posix-functions/sigaction.texi doc/posix-functions/siginterrupt.texi doc/posix-headers/signal.texi lib/sigaction.c lib/signal.in.h m4/sigaction.m4 m4/signal_h.m4 modules/sigaction modules/sigaction-tests modules/signal tests/test-sigaction.c
diffstat 13 files changed, 479 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat Jun 21 07:06:28 2008 -0600
+++ b/ChangeLog	Sat Jun 21 14:32:55 2008 -0600
@@ -1,5 +1,24 @@
 2008-06-21  Eric Blake  <ebb9@byu.net>
 
+	New module sigaction, for mingw.
+	* modules/sigaction: New module...
+	* modules/sigaction-tests: ...and its test.
+	* m4/sigaction.m4: New file.
+	* lib/sigaction.c: Likewise.
+	* tests/test-sigaction.c: Likewise.
+	* m4/signal_h.m4 (gl_SIGNAL_H_DEFAULTS): Add sigaction variables.
+	* modules/signal (Makefile.am): Likewise.
+	* lib/signal.in.h (!@HAVE_SIGACTION@): Define replacements when
+	needed.
+	* doc/posix-headers/signal.texi (signal.h): Mention provided
+	types.
+	* doc/posix-functions/siginterrupt.texi (siginterrupt): Mention
+	that sigaction is preferable.
+	* doc/posix-functions/sigaction.texi (sigaction): Mention new
+	module.
+	* MODULES.html.sh (Support for systems lacking POSIX:2001): Add
+	sigaction.
+
 	Improve robustness of sigprocmask by overriding signal.
 	* lib/signal.in.h (rpl_signal): Override signal when sigprocmask
 	is in use.
--- a/MODULES.html.sh	Sat Jun 21 07:06:28 2008 -0600
+++ b/MODULES.html.sh	Sat Jun 21 14:32:55 2008 -0600
@@ -2131,6 +2131,7 @@
   func_module rename
   func_module rmdir
   func_module search
+  func_module sigaction
   func_module sigprocmask
   func_module socklen
   func_module ssize_t
--- a/doc/posix-functions/sigaction.texi	Sat Jun 21 07:06:28 2008 -0600
+++ b/doc/posix-functions/sigaction.texi	Sat Jun 21 14:32:55 2008 -0600
@@ -4,17 +4,38 @@
 
 POSIX specification: @url{http://www.opengroup.org/susv3xsh/sigaction.html}
 
-Gnulib module: ---
+Gnulib module: sigaction
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+This function is missing on some platforms:
+mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-This function is missing on some platforms:
+POSIX recommends that when specifying SA_RESETHAND, SA_NODEFER must
+also be specified.
+
+@item
+Support for SA_ONSTACK is missing on some platforms:
+mingw, cygwin.
+
+@item
+Support for SA_SIGINFO is missing on some platforms:
+mingw, Interix 3.5.
+
+@item
+Support for SIGCHLD, and thus for SA_NOCLDSTOP and SA_NOCLDWAIT, is
+missing on some platforms:
 mingw.
+
+@item
+Support for SA_RESTART is missing on some platforms:
+mingw.
+
 @item
 The symbolic value @code{SIG_IGN} for the @code{SIGCHLD} signal is equivalent
 to a signal handler
--- a/doc/posix-functions/siginterrupt.texi	Sat Jun 21 07:06:28 2008 -0600
+++ b/doc/posix-functions/siginterrupt.texi	Sat Jun 21 14:32:55 2008 -0600
@@ -15,4 +15,7 @@
 @item
 This function is missing on some platforms:
 Solaris 2.5.1, mingw, Interix 3.5, BeOS.
+
+@item
+POSIX recommends using @code{sigaction} with SA_NODEFER instead.
 @end itemize
--- a/doc/posix-headers/signal.texi	Sat Jun 21 07:06:28 2008 -0600
+++ b/doc/posix-headers/signal.texi	Sat Jun 21 14:32:55 2008 -0600
@@ -3,12 +3,24 @@
 
 POSIX specification: @url{http://www.opengroup.org/susv3xbd/signal.h.html}
 
-Gnulib module: ---
+Gnulib module: signal
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+@code{sigset_t} is only declared in <sys/types.h> on some platforms:
+mingw.
+
+@item
+@code{struct sigaction} and @code{siginfo_t} are missing on some
+platforms:
+mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
+@item
+@code{struct sigaction} lacks the @code{sa_sigaction} member on some
+platforms; this can also be detected by whether @code{SA_SIGINFO} is defined:
+Interix 3.5.
 @end itemize
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/sigaction.c	Sat Jun 21 14:32:55 2008 -0600
@@ -0,0 +1,187 @@
+/* POSIX compatible signal blocking.
+   Copyright (C) 2008 Free Software Foundation, Inc.
+   Written by Eric Blake <ebb9@byu.net>, 2008.
+
+   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 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
+   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, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <signal.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/* This implementation of sigaction is tailored to Woe32 behavior:
+   signal() has SysV semantics (ie. the handler is uninstalled before
+   it is invoked).  This is an inherent data race if an asynchronous
+   signal is sent twice in a row before we can reinstall our handler,
+   but there's nothing we can do about it.  Meanwhile, sigprocmask()
+   is not present, and while we can use the gnulib replacement to
+   provide critical sections, it too suffers from potential data races
+   in the face of an ill-timed asynchronous signal.  And we compound
+   the situation by reading static storage in a signal handler, which
+   POSIX warns is not generically async-signal-safe.  Oh well.
+
+   Additionally, SIGCHLD is not defined, so we don't implement
+   SA_NOCLDSTOP or SA_NOCLDWAIT; sigaltstack() is not present, so we
+   don't implement SA_ONSTACK; and siginterrupt() is not present, so
+   we don't implement SA_RESTART.  Supporting SA_SIGINFO is impossible
+   to do portably.
+
+   POSIX states that an application should not mix signal() and
+   sigaction().  We support the use of signal() within the gnulib
+   sigprocmask() substitute, but all other application code linked
+   with this module should stick with only sigaction().  */
+
+/* Check some of our assumptions.  */
+#if defined SIGCHLD || defined HAVE_SIGALTSTACK || defined HAVE_SIGINTERRUPT
+# error "Revisit the assumptions made in the sigaction module"
+#endif
+
+/* Out-of-range substitutes make a good fallback for uncatchable
+   signals.  */
+#ifndef SIGKILL
+# define SIGKILL (-1)
+#endif
+#ifndef SIGSTOP
+# define SIGSTOP (-1)
+#endif
+
+/* A signal handler.  */
+typedef void (*handler_t) (int signal);
+
+/* Set of current actions.  If sa_handler for an entry is NULL, then
+   that signal is not currently handled by the sigaction handler.  */
+static struct sigaction volatile action_array[NSIG] /* = 0 */;
+
+/* Signal handler that is installed for signals.  */
+static void
+sigaction_handler (int sig)
+{
+  handler_t handler;
+  sigset_t mask;
+  sigset_t oldmask;
+  int saved_errno = errno;
+  if (sig < 0 || NSIG <= sig || !action_array[sig].sa_handler)
+    {
+      /* Unexpected situation; be careful to avoid recursive abort.  */
+      if (sig == SIGABRT)
+	signal (SIGABRT, SIG_DFL);
+      abort ();
+    }
+
+  /* Reinstall the signal handler when required; otherwise update the
+     bookkeeping so that the user's handler may call sigaction and get
+     accurate results.  We know the signal isn't currently blocked, or
+     we wouldn't be in its handler, therefore we know that we are not
+     interrupting a sigaction() call.  There is a race where any
+     asynchronous instance of the same signal occurring before we
+     reinstall the handler will trigger the default handler; oh
+     well.  */
+  handler = action_array[sig].sa_handler;
+  if ((action_array[sig].sa_flags & SA_RESETHAND) == 0)
+    signal (sig, sigaction_handler);
+  else
+    action_array[sig].sa_handler = NULL;
+
+  /* Block appropriate signals.  */
+  mask = action_array[sig].sa_mask;
+  if ((action_array[sig].sa_flags & SA_NODEFER) == 0)
+    sigaddset (&mask, sig);
+  sigprocmask (SIG_BLOCK, &mask, &oldmask);
+
+  /* Invoke the user's handler, then restore prior mask.  */
+  errno = saved_errno;
+  handler (sig);
+  saved_errno = errno;
+  sigprocmask (SIG_SETMASK, &oldmask, NULL);
+  errno = saved_errno;
+}
+
+/* Change and/or query the action that will be taken on delivery of
+   signal SIG.  If not NULL, ACT describes the new behavior.  If not
+   NULL, OACT is set to the prior behavior.  Return 0 on success, or
+   set errno and return -1 on failure.  */
+int
+sigaction (int sig, const struct sigaction *restrict act,
+           struct sigaction *restrict oact)
+{
+  sigset_t mask;
+  sigset_t oldmask;
+  int saved_errno;
+
+  if (sig < 0 || NSIG <= sig || sig == SIGKILL || sig == SIGSTOP
+      || (act && act->sa_handler == SIG_ERR))
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  /* POSIX requires sigaction() to be async-signal-safe.  In other
+     words, if an asynchronous signal can occur while we are anywhere
+     inside this function, the user's handler could then call
+     sigaction() recursively and expect consistent results.  We meet
+     this rule by using sigprocmask to block all signals before
+     modifying any data structure that could be read from a signal
+     handler; this works since we know that the gnulib sigprocmask
+     replacement does not try to use sigaction() from its handler.  */
+  if (!act && !oact)
+    return 0;
+  sigfillset (&mask);
+  sigprocmask (SIG_BLOCK, &mask, &oldmask);
+  if (oact)
+    {
+      if (action_array[sig].sa_handler)
+        *oact = action_array[sig];
+      else
+        {
+          /* Safe to change the handler at will here, since all
+             signals are currently blocked.  */
+          oact->sa_handler = signal (sig, SIG_DFL);
+          if (oact->sa_handler == SIG_ERR)
+            goto failure;
+          signal (sig, oact->sa_handler);
+          oact->sa_flags = SA_RESETHAND | SA_NODEFER;
+          sigemptyset (&oact->sa_mask);
+        }
+    }
+
+  if (act)
+    {
+      /* Safe to install the handler before updating action_array,
+         since all signals are currently blocked.  */
+      if (act->sa_handler == SIG_DFL || act->sa_handler == SIG_IGN)
+        {
+          if (signal (sig, act->sa_handler) == SIG_ERR)
+            goto failure;
+          action_array[sig].sa_handler = NULL;
+        }
+      else
+        {
+          if (signal (sig, sigaction_handler) == SIG_ERR)
+            goto failure;
+          action_array[sig] = *act;
+        }
+    }
+  sigprocmask (SIG_SETMASK, &oldmask, NULL);
+  return 0;
+
+ failure:
+  saved_errno = errno;
+  sigprocmask (SIG_SETMASK, &oldmask, NULL);
+  errno = saved_errno;
+  return -1;
+}
--- a/lib/signal.in.h	Sat Jun 21 07:06:28 2008 -0600
+++ b/lib/signal.in.h	Sat Jun 21 14:32:55 2008 -0600
@@ -34,9 +34,7 @@
 /* The definition of GL_LINK_WARNING is copied here.  */
 
 /* Mingw defines sigset_t not in <signal.h>, but in <sys/types.h>.  */
-#if !@HAVE_POSIX_SIGNALBLOCKING@
-# include <sys/types.h>
-#endif
+#include <sys/types.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -91,7 +89,63 @@
    handler.  */
 extern void (*signal (int sig, void (*func) (int))) (int);
 
-#endif
+#endif /* !@HAVE_POSIX_SIGNALBLOCKING@ */
+
+#if !@HAVE_SIGACTION@
+
+# if !@HAVE_SIGINFO_T@
+/* Present to allow compilation, but unsupported by gnulib.  */
+union sigval
+{
+  int sival_int;
+  void *sival_ptr;
+};
+
+/* Present to allow compilation, but unsupported by gnulib.  */
+struct siginfo_t
+{
+  int si_signo;
+  int si_code;
+  int si_errno;
+  pid_t si_pid;
+  uid_t si_uid;
+  void *si_addr;
+  int si_status;
+  long si_band;
+  union sigval si_value;
+};
+typedef struct siginfo_t siginfo_t;
+# endif /* !@HAVE_SIGINFO_T@ */
+
+  /* Due to autoconf conventions, we can't tell if HAVE_SIGACTION
+     means we have the type or means we have the function.  We assume
+     that all implementations either have both or neither.  */
+
+struct sigaction
+{
+  union
+  {
+    void (*_sa_handler) (int);
+    /* Present to allow compilation, but unsupported by gnulib.  POSIX
+       says that implementations may, but not must, make sa_sigaction
+       overlap with sa_handler, but we know of no implementation where
+       they do not overlap.  */
+    void (*_sa_sigaction) (int, siginfo_t *, void *);
+  } _sa_func;
+  sigset_t sa_mask;
+  /* Not all POSIX flags are supported.  */
+  int sa_flags;
+};
+# define sa_handler _sa_func._sa_handler
+# define sa_sigaction _sa_func._sa_sigaction
+/* Unsupported flags are not present.  */
+# define SA_RESETHAND 1
+# define SA_NODEFER 2
+
+extern int sigaction (int, const struct sigaction *restrict,
+                      struct sigaction *restrict);
+
+#endif /* !@HAVE_SIGACTION@ */
 
 
 #ifdef __cplusplus
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m4/sigaction.m4	Sat Jun 21 14:32:55 2008 -0600
@@ -0,0 +1,35 @@
+# sigaction.m4 serial 1
+dnl Copyright (C) 2008 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# Determine if sigaction interface is present.
+AC_DEFUN([gl_SIGACTION],
+[
+  dnl Due to autoconf conventions, we can't tell if HAVE_SIGACTION
+  dnl means we have the type or means we have the function.  We assume
+  dnl that all implementations either have both or neither.
+  AC_REPLACE_FUNCS([sigaction])
+  if test $ac_cv_func_sigaction = no ; then
+    HAVE_SIGACTION=0
+    AC_SUBST([HAVE_SIGACTION])
+    gl_PREREQ_SIGACTION
+  fi
+])
+
+# Prerequisites of the part of lib/signal.in.h and of lib/sigprocmask.c.
+AC_DEFUN([gl_PREREQ_SIGACTION],
+[
+  AC_REQUIRE([AC_C_RESTRICT])
+  AC_REQUIRE([AC_TYPE_UID_T])
+  AC_REQUIRE([gl_SIGNAL_H_DEFAULTS])
+  AC_CHECK_FUNCS_ONCE([sigaltstack siginterrupt])
+  AC_CHECK_TYPES([siginfo_t], [], [], [[
+#include <signal.h>
+  ]])
+  if test $ac_cv_type_siginfo_t = no; then
+    HAVE_SIGINFO_T=0
+    AC_SUBST([HAVE_SIGINFO_T])
+  fi
+])
--- a/m4/signal_h.m4	Sat Jun 21 07:06:28 2008 -0600
+++ b/m4/signal_h.m4	Sat Jun 21 14:32:55 2008 -0600
@@ -1,5 +1,5 @@
-# signal_h.m4 serial 3
-dnl Copyright (C) 2007 Free Software Foundation, Inc.
+# signal_h.m4 serial 4
+dnl Copyright (C) 2007, 2008 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
@@ -20,7 +20,10 @@
 AC_DEFUN([gl_SIGNAL_H_DEFAULTS],
 [
   GNULIB_SIGPROCMASK=0;        AC_SUBST([GNULIB_SIGPROCMASK])
+  GNULIB_SIGACTION=0;          AC_SUBST([GNULIB_SIGACTION])
   dnl Assume proper GNU behavior unless another module says otherwise.
   HAVE_POSIX_SIGNALBLOCKING=1; AC_SUBST([HAVE_POSIX_SIGNALBLOCKING])
   HAVE_SIGSET_T=1;             AC_SUBST([HAVE_SIGSET_T])
+  HAVE_SIGINFO_T=1;            AC_SUBST([HAVE_SIGINFO_T])
+  HAVE_SIGACTION=1;            AC_SUBST([HAVE_SIGACTION])
 ])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/sigaction	Sat Jun 21 14:32:55 2008 -0600
@@ -0,0 +1,25 @@
+Description:
+POSIX compatible signal handlers.
+
+Files:
+lib/sigaction.c
+m4/sigaction.m4
+
+Depends-on:
+signal
+sigprocmask
+
+configure.ac:
+gl_SIGACTION
+gl_SIGNAL_MODULE_INDICATOR([sigaction])
+
+Makefile.am:
+
+Include:
+<signal.h>
+
+License:
+LGPL
+
+Maintainer:
+Eric Blake
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/sigaction-tests	Sat Jun 21 14:32:55 2008 -0600
@@ -0,0 +1,10 @@
+Files:
+tests/test-sigaction.c
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-sigaction
+check_PROGRAMS += test-sigaction
--- a/modules/signal	Sat Jun 21 07:06:28 2008 -0600
+++ b/modules/signal	Sat Jun 21 14:32:55 2008 -0600
@@ -23,8 +23,11 @@
 	  sed -e 's/@''INCLUDE_NEXT''@/$(INCLUDE_NEXT)/g' \
 	      -e 's|@''NEXT_SIGNAL_H''@|$(NEXT_SIGNAL_H)|g' \
 	      -e 's|@''GNULIB_SIGPROCMASK''@|$(GNULIB_SIGPROCMASK)|g' \
+	      -e 's|@''GNULIB_SIGACTION''@|$(GNULIB_SIGACTION)|g' \
 	      -e 's|@''HAVE_POSIX_SIGNALBLOCKING''@|$(HAVE_POSIX_SIGNALBLOCKING)|g' \
 	      -e 's|@''HAVE_SIGSET_T''@|$(HAVE_SIGSET_T)|g' \
+	      -e 's|@''HAVE_SIGINFO_T''@|$(HAVE_SIGINFO_T)|g' \
+	      -e 's|@''HAVE_SIGACTION''@|$(HAVE_SIGACTION)|g' \
 	      -e '/definition of GL_LINK_WARNING/r $(LINK_WARNING_H)' \
 	      < $(srcdir)/signal.in.h; \
 	} > $@-t
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-sigaction.c	Sat Jun 21 14:32:55 2008 -0600
@@ -0,0 +1,97 @@
+/* Test of sigaction() function.
+   Copyright (C) 2008 Free Software Foundation, Inc.
+
+   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 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
+   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, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Eric Blake <ebb9@byu.net>, 2008.  */
+
+#include <config.h>
+
+#include <signal.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define ASSERT(expr) \
+  do									     \
+    {									     \
+      if (!(expr))							     \
+        {								     \
+          fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
+          fflush (stderr);						     \
+          signal (SIGABRT, SIG_DFL);					     \
+          abort ();							     \
+        }								     \
+    }									     \
+  while (0)
+
+#ifndef SA_SIGINFO
+# define SA_SIGINFO 0
+#endif
+
+/* This test is unsafe in the presence of an asynchronous SIGABRT,
+   because we install a signal-handler that is intentionally not
+   async-safe.  Hopefully, this does not lead to too many reports of
+   false failures, since people don't generally use 'kill -s SIGABRT'
+   to end a runaway program.  */
+
+static void
+handler (int sig)
+{
+  static int entry_count;
+  struct sigaction sa;
+  ASSERT (sig == SIGABRT);
+  ASSERT (sigaction (SIGABRT, NULL, &sa) == 0);
+  ASSERT ((sa.sa_flags & SA_SIGINFO) == 0);
+  switch (entry_count++)
+    {
+    case 0:
+      ASSERT ((sa.sa_flags & SA_RESETHAND) == 0);
+      ASSERT (sa.sa_handler == handler);
+      break;
+    case 1:
+      ASSERT (sa.sa_handler == SIG_DFL);
+      break;
+    default:
+      ASSERT (0);
+    }
+}
+
+int
+main (int argc, char *argv[])
+{
+  struct sigaction sa;
+  struct sigaction old_sa;
+  sa.sa_handler = handler;
+  sa.sa_flags = 0;
+  ASSERT (sigemptyset (&sa.sa_mask) == 0);
+  ASSERT (sigaction (SIGABRT, &sa, NULL) == 0);
+  ASSERT (raise (SIGABRT) == 0);
+  sa.sa_flags = SA_RESETHAND | SA_NODEFER;
+  ASSERT (sigaction (SIGABRT, &sa, &old_sa) == 0);
+  ASSERT (old_sa.sa_flags == 0);
+  ASSERT (old_sa.sa_handler == handler);
+  ASSERT (raise (SIGABRT) == 0);
+  sa.sa_handler = SIG_DFL;
+  ASSERT (sigaction (SIGABRT, &sa, &old_sa) == 0);
+  ASSERT ((old_sa.sa_flags & SA_SIGINFO) == 0);
+  ASSERT (old_sa.sa_handler == SIG_DFL);
+  sa.sa_handler = SIG_IGN;
+  ASSERT (sigaction (SIGABRT, &sa, NULL) == 0);
+  ASSERT (raise (SIGABRT) == 0);
+  ASSERT (sigaction (SIGABRT, NULL, &old_sa) == 0);
+  ASSERT (old_sa.sa_handler == SIG_IGN);
+  ASSERT (raise (SIGABRT) == 0);
+  return 0;
+}