Blame lib/sigprocmask.c

Packit 33f14e
/* POSIX compatible signal blocking.
Packit 33f14e
   Copyright (C) 2006-2017 Free Software Foundation, Inc.
Packit 33f14e
   Written by Bruno Haible <bruno@clisp.org>, 2006.
Packit 33f14e
Packit 33f14e
   This program is free software: you can redistribute it and/or modify
Packit 33f14e
   it under the terms of the GNU General Public License as published by
Packit 33f14e
   the Free Software Foundation; either version 3 of the License, or
Packit 33f14e
   (at your option) any later version.
Packit 33f14e
Packit 33f14e
   This program is distributed in the hope that it will be useful,
Packit 33f14e
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 33f14e
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 33f14e
   GNU General Public License for more details.
Packit 33f14e
Packit 33f14e
   You should have received a copy of the GNU General Public License
Packit 33f14e
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit 33f14e
Packit 33f14e
#include <config.h>
Packit 33f14e
Packit 33f14e
/* Specification.  */
Packit 33f14e
#include <signal.h>
Packit 33f14e
Packit 33f14e
#include <errno.h>
Packit 33f14e
#include <stdint.h>
Packit 33f14e
#include <stdlib.h>
Packit 33f14e
Packit 33f14e
#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
Packit 33f14e
# include "msvc-inval.h"
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
/* We assume that a platform without POSIX signal blocking functions
Packit 33f14e
   also does not have the POSIX sigaction() function, only the
Packit 33f14e
   signal() function.  We also assume signal() has SysV semantics,
Packit 33f14e
   where any handler is uninstalled prior to being invoked.  This is
Packit 33f14e
   true for native Windows platforms.  */
Packit 33f14e
Packit 33f14e
/* We use raw signal(), but also provide a wrapper rpl_signal() so
Packit 33f14e
   that applications can query or change a blocked signal.  */
Packit 33f14e
#undef signal
Packit 33f14e
Packit 33f14e
/* Provide invalid signal numbers as fallbacks if the uncatchable
Packit 33f14e
   signals are not defined.  */
Packit 33f14e
#ifndef SIGKILL
Packit 33f14e
# define SIGKILL (-1)
Packit 33f14e
#endif
Packit 33f14e
#ifndef SIGSTOP
Packit 33f14e
# define SIGSTOP (-1)
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
/* On native Windows, as of 2008, the signal SIGABRT_COMPAT is an alias
Packit 33f14e
   for the signal SIGABRT.  Only one signal handler is stored for both
Packit 33f14e
   SIGABRT and SIGABRT_COMPAT.  SIGABRT_COMPAT is not a signal of its own.  */
Packit 33f14e
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
Packit 33f14e
# undef SIGABRT_COMPAT
Packit 33f14e
# define SIGABRT_COMPAT 6
Packit 33f14e
#endif
Packit 33f14e
#ifdef SIGABRT_COMPAT
Packit 33f14e
# define SIGABRT_COMPAT_MASK (1U << SIGABRT_COMPAT)
Packit 33f14e
#else
Packit 33f14e
# define SIGABRT_COMPAT_MASK 0
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
typedef void (*handler_t) (int);
Packit 33f14e
Packit 33f14e
#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
Packit 33f14e
static handler_t
Packit 33f14e
signal_nothrow (int sig, handler_t handler)
Packit 33f14e
{
Packit 33f14e
  handler_t result;
Packit 33f14e
Packit 33f14e
  TRY_MSVC_INVAL
Packit 33f14e
    {
Packit 33f14e
      result = signal (sig, handler);
Packit 33f14e
    }
Packit 33f14e
  CATCH_MSVC_INVAL
Packit 33f14e
    {
Packit 33f14e
      result = SIG_ERR;
Packit 33f14e
      errno = EINVAL;
Packit 33f14e
    }
Packit 33f14e
  DONE_MSVC_INVAL;
Packit 33f14e
Packit 33f14e
  return result;
Packit 33f14e
}
Packit 33f14e
# define signal signal_nothrow
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
/* Handling of gnulib defined signals.  */
Packit 33f14e
Packit 33f14e
#if GNULIB_defined_SIGPIPE
Packit 33f14e
static handler_t SIGPIPE_handler = SIG_DFL;
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
#if GNULIB_defined_SIGPIPE
Packit 33f14e
static handler_t
Packit 33f14e
ext_signal (int sig, handler_t handler)
Packit 33f14e
{
Packit 33f14e
  switch (sig)
Packit 33f14e
    {
Packit 33f14e
    case SIGPIPE:
Packit 33f14e
      {
Packit 33f14e
        handler_t old_handler = SIGPIPE_handler;
Packit 33f14e
        SIGPIPE_handler = handler;
Packit 33f14e
        return old_handler;
Packit 33f14e
      }
Packit 33f14e
    default: /* System defined signal */
Packit 33f14e
      return signal (sig, handler);
Packit 33f14e
    }
Packit 33f14e
}
Packit 33f14e
# undef signal
Packit 33f14e
# define signal ext_signal
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
int
Packit 33f14e
sigismember (const sigset_t *set, int sig)
Packit 33f14e
{
Packit 33f14e
  if (sig >= 0 && sig < NSIG)
Packit 33f14e
    {
Packit 33f14e
      #ifdef SIGABRT_COMPAT
Packit 33f14e
      if (sig == SIGABRT_COMPAT)
Packit 33f14e
        sig = SIGABRT;
Packit 33f14e
      #endif
Packit 33f14e
Packit 33f14e
      return (*set >> sig) & 1;
Packit 33f14e
    }
Packit 33f14e
  else
Packit 33f14e
    return 0;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
int
Packit 33f14e
sigemptyset (sigset_t *set)
Packit 33f14e
{
Packit 33f14e
  *set = 0;
Packit 33f14e
  return 0;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
int
Packit 33f14e
sigaddset (sigset_t *set, int sig)
Packit 33f14e
{
Packit 33f14e
  if (sig >= 0 && sig < NSIG)
Packit 33f14e
    {
Packit 33f14e
      #ifdef SIGABRT_COMPAT
Packit 33f14e
      if (sig == SIGABRT_COMPAT)
Packit 33f14e
        sig = SIGABRT;
Packit 33f14e
      #endif
Packit 33f14e
Packit 33f14e
      *set |= 1U << sig;
Packit 33f14e
      return 0;
Packit 33f14e
    }
Packit 33f14e
  else
Packit 33f14e
    {
Packit 33f14e
      errno = EINVAL;
Packit 33f14e
      return -1;
Packit 33f14e
    }
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
int
Packit 33f14e
sigdelset (sigset_t *set, int sig)
Packit 33f14e
{
Packit 33f14e
  if (sig >= 0 && sig < NSIG)
Packit 33f14e
    {
Packit 33f14e
      #ifdef SIGABRT_COMPAT
Packit 33f14e
      if (sig == SIGABRT_COMPAT)
Packit 33f14e
        sig = SIGABRT;
Packit 33f14e
      #endif
Packit 33f14e
Packit 33f14e
      *set &= ~(1U << sig);
Packit 33f14e
      return 0;
Packit 33f14e
    }
Packit 33f14e
  else
Packit 33f14e
    {
Packit 33f14e
      errno = EINVAL;
Packit 33f14e
      return -1;
Packit 33f14e
    }
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
Packit 33f14e
int
Packit 33f14e
sigfillset (sigset_t *set)
Packit 33f14e
{
Packit 33f14e
  *set = ((2U << (NSIG - 1)) - 1) & ~ SIGABRT_COMPAT_MASK;
Packit 33f14e
  return 0;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Set of currently blocked signals.  */
Packit 33f14e
static volatile sigset_t blocked_set /* = 0 */;
Packit 33f14e
Packit 33f14e
/* Set of currently blocked and pending signals.  */
Packit 33f14e
static volatile sig_atomic_t pending_array[NSIG] /* = { 0 } */;
Packit 33f14e
Packit 33f14e
/* Signal handler that is installed for blocked signals.  */
Packit 33f14e
static void
Packit 33f14e
blocked_handler (int sig)
Packit 33f14e
{
Packit 33f14e
  /* Reinstall the handler, in case the signal occurs multiple times
Packit 33f14e
     while blocked.  There is an inherent race where an asynchronous
Packit 33f14e
     signal in between when the kernel uninstalled the handler and
Packit 33f14e
     when we reinstall it will trigger the default handler; oh
Packit 33f14e
     well.  */
Packit 33f14e
  signal (sig, blocked_handler);
Packit 33f14e
  if (sig >= 0 && sig < NSIG)
Packit 33f14e
    pending_array[sig] = 1;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
int
Packit 33f14e
sigpending (sigset_t *set)
Packit 33f14e
{
Packit 33f14e
  sigset_t pending = 0;
Packit 33f14e
  int sig;
Packit 33f14e
Packit 33f14e
  for (sig = 0; sig < NSIG; sig++)
Packit 33f14e
    if (pending_array[sig])
Packit 33f14e
      pending |= 1U << sig;
Packit 33f14e
  *set = pending;
Packit 33f14e
  return 0;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* The previous signal handlers.
Packit 33f14e
   Only the array elements corresponding to blocked signals are relevant.  */
Packit 33f14e
static volatile handler_t old_handlers[NSIG];
Packit 33f14e
Packit 33f14e
int
Packit 33f14e
sigprocmask (int operation, const sigset_t *set, sigset_t *old_set)
Packit 33f14e
{
Packit 33f14e
  if (old_set != NULL)
Packit 33f14e
    *old_set = blocked_set;
Packit 33f14e
Packit 33f14e
  if (set != NULL)
Packit 33f14e
    {
Packit 33f14e
      sigset_t new_blocked_set;
Packit 33f14e
      sigset_t to_unblock;
Packit 33f14e
      sigset_t to_block;
Packit 33f14e
Packit 33f14e
      switch (operation)
Packit 33f14e
        {
Packit 33f14e
        case SIG_BLOCK:
Packit 33f14e
          new_blocked_set = blocked_set | *set;
Packit 33f14e
          break;
Packit 33f14e
        case SIG_SETMASK:
Packit 33f14e
          new_blocked_set = *set;
Packit 33f14e
          break;
Packit 33f14e
        case SIG_UNBLOCK:
Packit 33f14e
          new_blocked_set = blocked_set & ~*set;
Packit 33f14e
          break;
Packit 33f14e
        default:
Packit 33f14e
          errno = EINVAL;
Packit 33f14e
          return -1;
Packit 33f14e
        }
Packit 33f14e
      to_unblock = blocked_set & ~new_blocked_set;
Packit 33f14e
      to_block = new_blocked_set & ~blocked_set;
Packit 33f14e
Packit 33f14e
      if (to_block != 0)
Packit 33f14e
        {
Packit 33f14e
          int sig;
Packit 33f14e
Packit 33f14e
          for (sig = 0; sig < NSIG; sig++)
Packit 33f14e
            if ((to_block >> sig) & 1)
Packit 33f14e
              {
Packit 33f14e
                pending_array[sig] = 0;
Packit 33f14e
                if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR)
Packit 33f14e
                  blocked_set |= 1U << sig;
Packit 33f14e
              }
Packit 33f14e
        }
Packit 33f14e
Packit 33f14e
      if (to_unblock != 0)
Packit 33f14e
        {
Packit 33f14e
          sig_atomic_t received[NSIG];
Packit 33f14e
          int sig;
Packit 33f14e
Packit 33f14e
          for (sig = 0; sig < NSIG; sig++)
Packit 33f14e
            if ((to_unblock >> sig) & 1)
Packit 33f14e
              {
Packit 33f14e
                if (signal (sig, old_handlers[sig]) != blocked_handler)
Packit 33f14e
                  /* The application changed a signal handler while the signal
Packit 33f14e
                     was blocked, bypassing our rpl_signal replacement.
Packit 33f14e
                     We don't support this.  */
Packit 33f14e
                  abort ();
Packit 33f14e
                received[sig] = pending_array[sig];
Packit 33f14e
                blocked_set &= ~(1U << sig);
Packit 33f14e
                pending_array[sig] = 0;
Packit 33f14e
              }
Packit 33f14e
            else
Packit 33f14e
              received[sig] = 0;
Packit 33f14e
Packit 33f14e
          for (sig = 0; sig < NSIG; sig++)
Packit 33f14e
            if (received[sig])
Packit 33f14e
              raise (sig);
Packit 33f14e
        }
Packit 33f14e
    }
Packit 33f14e
  return 0;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Install the handler FUNC for signal SIG, and return the previous
Packit 33f14e
   handler.  */
Packit 33f14e
handler_t
Packit 33f14e
rpl_signal (int sig, handler_t handler)
Packit 33f14e
{
Packit 33f14e
  /* We must provide a wrapper, so that a user can query what handler
Packit 33f14e
     they installed even if that signal is currently blocked.  */
Packit 33f14e
  if (sig >= 0 && sig < NSIG && sig != SIGKILL && sig != SIGSTOP
Packit 33f14e
      && handler != SIG_ERR)
Packit 33f14e
    {
Packit 33f14e
      #ifdef SIGABRT_COMPAT
Packit 33f14e
      if (sig == SIGABRT_COMPAT)
Packit 33f14e
        sig = SIGABRT;
Packit 33f14e
      #endif
Packit 33f14e
Packit 33f14e
      if (blocked_set & (1U << sig))
Packit 33f14e
        {
Packit 33f14e
          /* POSIX states that sigprocmask and signal are both
Packit 33f14e
             async-signal-safe.  This is not true of our
Packit 33f14e
             implementation - there is a slight data race where an
Packit 33f14e
             asynchronous interrupt on signal A can occur after we
Packit 33f14e
             install blocked_handler but before we have updated
Packit 33f14e
             old_handlers for signal B, such that handler A can see
Packit 33f14e
             stale information if it calls signal(B).  Oh well -
Packit 33f14e
             signal handlers really shouldn't try to manipulate the
Packit 33f14e
             installed handlers of unrelated signals.  */
Packit 33f14e
          handler_t result = old_handlers[sig];
Packit 33f14e
          old_handlers[sig] = handler;
Packit 33f14e
          return result;
Packit 33f14e
        }
Packit 33f14e
      else
Packit 33f14e
        return signal (sig, handler);
Packit 33f14e
    }
Packit 33f14e
  else
Packit 33f14e
    {
Packit 33f14e
      errno = EINVAL;
Packit 33f14e
      return SIG_ERR;
Packit 33f14e
    }
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
#if GNULIB_defined_SIGPIPE
Packit 33f14e
/* Raise the signal SIGPIPE.  */
Packit 33f14e
int
Packit 33f14e
_gl_raise_SIGPIPE (void)
Packit 33f14e
{
Packit 33f14e
  if (blocked_set & (1U << SIGPIPE))
Packit 33f14e
    pending_array[SIGPIPE] = 1;
Packit 33f14e
  else
Packit 33f14e
    {
Packit 33f14e
      handler_t handler = SIGPIPE_handler;
Packit 33f14e
      if (handler == SIG_DFL)
Packit 33f14e
        exit (128 + SIGPIPE);
Packit 33f14e
      else if (handler != SIG_IGN)
Packit 33f14e
        (*handler) (SIGPIPE);
Packit 33f14e
    }
Packit 33f14e
  return 0;
Packit 33f14e
}
Packit 33f14e
#endif