Blame lib/sigprocmask.c

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