strtoumax: fix typo in previous commit.
[gnulib.git] / lib / sigprocmask.c
index 54e9c68..8de3777 100644 (file)
@@ -1,5 +1,5 @@
 /* POSIX compatible signal blocking.
-   Copyright (C) 2006-2008 Free Software Foundation, Inc.
+   Copyright (C) 2006-2013 Free Software Foundation, Inc.
    Written by Bruno Haible <bruno@clisp.org>, 2006.
 
    This program is free software: you can redistribute it and/or modify
 #include <stdint.h>
 #include <stdlib.h>
 
-#include "sig-handler.h"
+#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
+# include "msvc-inval.h"
+#endif
 
 /* We assume that a platform without POSIX signal blocking functions
    also does not have the POSIX sigaction() function, only the
    signal() function.  We also assume signal() has SysV semantics,
    where any handler is uninstalled prior to being invoked.  This is
-   true for Woe32 platforms.  */
+   true for native Windows platforms.  */
 
 /* We use raw signal(), but also provide a wrapper rpl_signal() so
    that applications can query or change a blocked signal.  */
 # define SIGSTOP (-1)
 #endif
 
+/* On native Windows, as of 2008, the signal SIGABRT_COMPAT is an alias
+   for the signal SIGABRT.  Only one signal handler is stored for both
+   SIGABRT and SIGABRT_COMPAT.  SIGABRT_COMPAT is not a signal of its own.  */
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+# undef SIGABRT_COMPAT
+# define SIGABRT_COMPAT 6
+#endif
+#ifdef SIGABRT_COMPAT
+# define SIGABRT_COMPAT_MASK (1U << SIGABRT_COMPAT)
+#else
+# define SIGABRT_COMPAT_MASK 0
+#endif
+
+typedef void (*handler_t) (int);
+
+#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
+static handler_t
+signal_nothrow (int sig, handler_t handler)
+{
+  handler_t result;
+
+  TRY_MSVC_INVAL
+    {
+      result = signal (sig, handler);
+    }
+  CATCH_MSVC_INVAL
+    {
+      result = SIG_ERR;
+      errno = EINVAL;
+    }
+  DONE_MSVC_INVAL;
+
+  return result;
+}
+# define signal signal_nothrow
+#endif
+
+/* Handling of gnulib defined signals.  */
+
+#if GNULIB_defined_SIGPIPE
+static handler_t SIGPIPE_handler = SIG_DFL;
+#endif
+
+#if GNULIB_defined_SIGPIPE
+static handler_t
+ext_signal (int sig, handler_t handler)
+{
+  switch (sig)
+    {
+    case SIGPIPE:
+      {
+        handler_t old_handler = SIGPIPE_handler;
+        SIGPIPE_handler = handler;
+        return old_handler;
+      }
+    default: /* System defined signal */
+      return signal (sig, handler);
+    }
+}
+# undef signal
+# define signal ext_signal
+#endif
+
 int
 sigismember (const sigset_t *set, int sig)
 {
   if (sig >= 0 && sig < NSIG)
-    return (*set >> sig) & 1;
+    {
+      #ifdef SIGABRT_COMPAT
+      if (sig == SIGABRT_COMPAT)
+        sig = SIGABRT;
+      #endif
+
+      return (*set >> sig) & 1;
+    }
   else
     return 0;
 }
@@ -66,6 +138,11 @@ sigaddset (sigset_t *set, int sig)
 {
   if (sig >= 0 && sig < NSIG)
     {
+      #ifdef SIGABRT_COMPAT
+      if (sig == SIGABRT_COMPAT)
+        sig = SIGABRT;
+      #endif
+
       *set |= 1U << sig;
       return 0;
     }
@@ -81,6 +158,11 @@ sigdelset (sigset_t *set, int sig)
 {
   if (sig >= 0 && sig < NSIG)
     {
+      #ifdef SIGABRT_COMPAT
+      if (sig == SIGABRT_COMPAT)
+        sig = SIGABRT;
+      #endif
+
       *set &= ~(1U << sig);
       return 0;
     }
@@ -91,10 +173,11 @@ sigdelset (sigset_t *set, int sig)
     }
 }
 
+
 int
 sigfillset (sigset_t *set)
 {
-  *set = (2U << (NSIG - 1)) - 1;
+  *set = ((2U << (NSIG - 1)) - 1) & ~ SIGABRT_COMPAT_MASK;
   return 0;
 }
 
@@ -133,7 +216,7 @@ sigpending (sigset_t *set)
 
 /* The previous signal handlers.
    Only the array elements corresponding to blocked signals are relevant.  */
-static volatile sa_handler_t old_handlers[NSIG];
+static volatile handler_t old_handlers[NSIG];
 
 int
 sigprocmask (int operation, const sigset_t *set, sigset_t *old_set)
@@ -148,91 +231,96 @@ sigprocmask (int operation, const sigset_t *set, sigset_t *old_set)
       sigset_t to_block;
 
       switch (operation)
-       {
-       case SIG_BLOCK:
-         new_blocked_set = blocked_set | *set;
-         break;
-       case SIG_SETMASK:
-         new_blocked_set = *set;
-         break;
-       case SIG_UNBLOCK:
-         new_blocked_set = blocked_set & ~*set;
-         break;
-       default:
-         errno = EINVAL;
-         return -1;
-       }
+        {
+        case SIG_BLOCK:
+          new_blocked_set = blocked_set | *set;
+          break;
+        case SIG_SETMASK:
+          new_blocked_set = *set;
+          break;
+        case SIG_UNBLOCK:
+          new_blocked_set = blocked_set & ~*set;
+          break;
+        default:
+          errno = EINVAL;
+          return -1;
+        }
       to_unblock = blocked_set & ~new_blocked_set;
       to_block = new_blocked_set & ~blocked_set;
 
       if (to_block != 0)
-       {
-         int sig;
-
-         for (sig = 0; sig < NSIG; sig++)
-           if ((to_block >> sig) & 1)
-             {
-               pending_array[sig] = 0;
-               if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR)
-                 blocked_set |= 1U << sig;
-             }
-       }
+        {
+          int sig;
+
+          for (sig = 0; sig < NSIG; sig++)
+            if ((to_block >> sig) & 1)
+              {
+                pending_array[sig] = 0;
+                if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR)
+                  blocked_set |= 1U << sig;
+              }
+        }
 
       if (to_unblock != 0)
-       {
-         sig_atomic_t received[NSIG];
-         int sig;
-
-         for (sig = 0; sig < NSIG; sig++)
-           if ((to_unblock >> sig) & 1)
-             {
-               if (signal (sig, old_handlers[sig]) != blocked_handler)
-                 /* The application changed a signal handler while the signal
-                    was blocked, bypassing our rpl_signal replacement.
-                    We don't support this.  */
-                 abort ();
-               received[sig] = pending_array[sig];
-               blocked_set &= ~(1U << sig);
-               pending_array[sig] = 0;
-             }
-           else
-             received[sig] = 0;
-
-         for (sig = 0; sig < NSIG; sig++)
-           if (received[sig])
-             raise (sig);
-       }
+        {
+          sig_atomic_t received[NSIG];
+          int sig;
+
+          for (sig = 0; sig < NSIG; sig++)
+            if ((to_unblock >> sig) & 1)
+              {
+                if (signal (sig, old_handlers[sig]) != blocked_handler)
+                  /* The application changed a signal handler while the signal
+                     was blocked, bypassing our rpl_signal replacement.
+                     We don't support this.  */
+                  abort ();
+                received[sig] = pending_array[sig];
+                blocked_set &= ~(1U << sig);
+                pending_array[sig] = 0;
+              }
+            else
+              received[sig] = 0;
+
+          for (sig = 0; sig < NSIG; sig++)
+            if (received[sig])
+              raise (sig);
+        }
     }
   return 0;
 }
 
 /* Install the handler FUNC for signal SIG, and return the previous
    handler.  */
-sa_handler_t
-rpl_signal (int sig, sa_handler_t handler)
+handler_t
+rpl_signal (int sig, handler_t handler)
 {
   /* We must provide a wrapper, so that a user can query what handler
      they installed even if that signal is currently blocked.  */
   if (sig >= 0 && sig < NSIG && sig != SIGKILL && sig != SIGSTOP
       && handler != SIG_ERR)
     {
+      #ifdef SIGABRT_COMPAT
+      if (sig == SIGABRT_COMPAT)
+        sig = SIGABRT;
+      #endif
+
       if (blocked_set & (1U << sig))
-       {
-         /* POSIX states that sigprocmask and signal are both
-            async-signal-safe.  This is not true of our
-            implementation - there is a slight data race where an
-            asynchronous interrupt on signal A can occur after we
-            install blocked_handler but before we have updated
-            old_handlers for signal B, such that handler A can see
-            stale information if it calls signal(B).  Oh well -
-            signal handlers really shouldn't try to manipulate the
-            installed handlers of unrelated signals.  */
-         sa_handler_t result = old_handlers[sig];
-         old_handlers[sig] = handler;
-         return result;
-       }
+        {
+          /* POSIX states that sigprocmask and signal are both
+             async-signal-safe.  This is not true of our
+             implementation - there is a slight data race where an
+             asynchronous interrupt on signal A can occur after we
+             install blocked_handler but before we have updated
+             old_handlers for signal B, such that handler A can see
+             stale information if it calls signal(B).  Oh well -
+             signal handlers really shouldn't try to manipulate the
+             installed handlers of unrelated signals.  */
+          handler_t result = old_handlers[sig];
+          old_handlers[sig] = handler;
+          return result;
+        }
       else
-       return signal (sig, handler);
+        return signal (sig, handler);
     }
   else
     {
@@ -240,3 +328,22 @@ rpl_signal (int sig, sa_handler_t handler)
       return SIG_ERR;
     }
 }
+
+#if GNULIB_defined_SIGPIPE
+/* Raise the signal SIGPIPE.  */
+int
+_gl_raise_SIGPIPE (void)
+{
+  if (blocked_set & (1U << SIGPIPE))
+    pending_array[SIGPIPE] = 1;
+  else
+    {
+      handler_t handler = SIGPIPE_handler;
+      if (handler == SIG_DFL)
+        exit (128 + SIGPIPE);
+      else if (handler != SIG_IGN)
+        (*handler) (SIGPIPE);
+    }
+  return 0;
+}
+#endif