root/maint/gnulib/lib/sigprocmask.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. signal_nothrow
  2. ext_signal
  3. sigismember
  4. sigemptyset
  5. sigaddset
  6. sigdelset
  7. sigfillset
  8. blocked_handler
  9. sigpending
  10. sigprocmask
  11. rpl_signal
  12. _gl_raise_SIGPIPE

   1 /* POSIX compatible signal blocking.
   2    Copyright (C) 2006-2021 Free Software Foundation, Inc.
   3    Written by Bruno Haible <bruno@clisp.org>, 2006.
   4 
   5    This file is free software: you can redistribute it and/or modify
   6    it under the terms of the GNU Lesser General Public License as
   7    published by the Free Software Foundation; either version 2.1 of the
   8    License, or (at your option) any later version.
   9 
  10    This file is distributed in the hope that it will be useful,
  11    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13    GNU Lesser General Public License for more details.
  14 
  15    You should have received a copy of the GNU Lesser General Public License
  16    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  17 
  18 #include <config.h>
  19 
  20 /* Specification.  */
  21 #include <signal.h>
  22 
  23 #include <errno.h>
  24 #include <stdint.h>
  25 #include <stdlib.h>
  26 
  27 #if HAVE_MSVC_INVALID_PARAMETER_HANDLER
  28 # include "msvc-inval.h"
  29 #endif
  30 
  31 /* We assume that a platform without POSIX signal blocking functions
  32    also does not have the POSIX sigaction() function, only the
  33    signal() function.  We also assume signal() has SysV semantics,
  34    where any handler is uninstalled prior to being invoked.  This is
  35    true for native Windows platforms.  */
  36 
  37 /* We use raw signal(), but also provide a wrapper rpl_signal() so
  38    that applications can query or change a blocked signal.  */
  39 #undef signal
  40 
  41 /* Provide invalid signal numbers as fallbacks if the uncatchable
  42    signals are not defined.  */
  43 #ifndef SIGKILL
  44 # define SIGKILL (-1)
  45 #endif
  46 #ifndef SIGSTOP
  47 # define SIGSTOP (-1)
  48 #endif
  49 
  50 /* On native Windows, as of 2008, the signal SIGABRT_COMPAT is an alias
  51    for the signal SIGABRT.  Only one signal handler is stored for both
  52    SIGABRT and SIGABRT_COMPAT.  SIGABRT_COMPAT is not a signal of its own.  */
  53 #if defined _WIN32 && ! defined __CYGWIN__
  54 # undef SIGABRT_COMPAT
  55 # define SIGABRT_COMPAT 6
  56 #endif
  57 #ifdef SIGABRT_COMPAT
  58 # define SIGABRT_COMPAT_MASK (1U << SIGABRT_COMPAT)
  59 #else
  60 # define SIGABRT_COMPAT_MASK 0
  61 #endif
  62 
  63 typedef void (*handler_t) (int);
  64 
  65 #if HAVE_MSVC_INVALID_PARAMETER_HANDLER
  66 static handler_t
  67 signal_nothrow (int sig, handler_t handler)
     /* [previous][next][first][last][top][bottom][index][help] */
  68 {
  69   handler_t result;
  70 
  71   TRY_MSVC_INVAL
  72     {
  73       result = signal (sig, handler);
  74     }
  75   CATCH_MSVC_INVAL
  76     {
  77       result = SIG_ERR;
  78       errno = EINVAL;
  79     }
  80   DONE_MSVC_INVAL;
  81 
  82   return result;
  83 }
  84 # define signal signal_nothrow
  85 #endif
  86 
  87 /* Handling of gnulib defined signals.  */
  88 
  89 #if GNULIB_defined_SIGPIPE
  90 static handler_t SIGPIPE_handler = SIG_DFL;
  91 #endif
  92 
  93 #if GNULIB_defined_SIGPIPE
  94 static handler_t
  95 ext_signal (int sig, handler_t handler)
     /* [previous][next][first][last][top][bottom][index][help] */
  96 {
  97   switch (sig)
  98     {
  99     case SIGPIPE:
 100       {
 101         handler_t old_handler = SIGPIPE_handler;
 102         SIGPIPE_handler = handler;
 103         return old_handler;
 104       }
 105     default: /* System defined signal */
 106       return signal (sig, handler);
 107     }
 108 }
 109 # undef signal
 110 # define signal ext_signal
 111 #endif
 112 
 113 int
 114 sigismember (const sigset_t *set, int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 115 {
 116   if (sig >= 0 && sig < NSIG)
 117     {
 118       #ifdef SIGABRT_COMPAT
 119       if (sig == SIGABRT_COMPAT)
 120         sig = SIGABRT;
 121       #endif
 122 
 123       return (*set >> sig) & 1;
 124     }
 125   else
 126     return 0;
 127 }
 128 
 129 int
 130 sigemptyset (sigset_t *set)
     /* [previous][next][first][last][top][bottom][index][help] */
 131 {
 132   *set = 0;
 133   return 0;
 134 }
 135 
 136 int
 137 sigaddset (sigset_t *set, int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 138 {
 139   if (sig >= 0 && sig < NSIG)
 140     {
 141       #ifdef SIGABRT_COMPAT
 142       if (sig == SIGABRT_COMPAT)
 143         sig = SIGABRT;
 144       #endif
 145 
 146       *set |= 1U << sig;
 147       return 0;
 148     }
 149   else
 150     {
 151       errno = EINVAL;
 152       return -1;
 153     }
 154 }
 155 
 156 int
 157 sigdelset (sigset_t *set, int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 158 {
 159   if (sig >= 0 && sig < NSIG)
 160     {
 161       #ifdef SIGABRT_COMPAT
 162       if (sig == SIGABRT_COMPAT)
 163         sig = SIGABRT;
 164       #endif
 165 
 166       *set &= ~(1U << sig);
 167       return 0;
 168     }
 169   else
 170     {
 171       errno = EINVAL;
 172       return -1;
 173     }
 174 }
 175 
 176 
 177 int
 178 sigfillset (sigset_t *set)
     /* [previous][next][first][last][top][bottom][index][help] */
 179 {
 180   *set = ((2U << (NSIG - 1)) - 1) & ~ SIGABRT_COMPAT_MASK;
 181   return 0;
 182 }
 183 
 184 /* Set of currently blocked signals.  */
 185 static volatile sigset_t blocked_set /* = 0 */;
 186 
 187 /* Set of currently blocked and pending signals.  */
 188 static volatile sig_atomic_t pending_array[NSIG] /* = { 0 } */;
 189 
 190 /* Signal handler that is installed for blocked signals.  */
 191 static void
 192 blocked_handler (int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 193 {
 194   /* Reinstall the handler, in case the signal occurs multiple times
 195      while blocked.  There is an inherent race where an asynchronous
 196      signal in between when the kernel uninstalled the handler and
 197      when we reinstall it will trigger the default handler; oh
 198      well.  */
 199   signal (sig, blocked_handler);
 200   if (sig >= 0 && sig < NSIG)
 201     pending_array[sig] = 1;
 202 }
 203 
 204 int
 205 sigpending (sigset_t *set)
     /* [previous][next][first][last][top][bottom][index][help] */
 206 {
 207   sigset_t pending = 0;
 208   int sig;
 209 
 210   for (sig = 0; sig < NSIG; sig++)
 211     if (pending_array[sig])
 212       pending |= 1U << sig;
 213   *set = pending;
 214   return 0;
 215 }
 216 
 217 /* The previous signal handlers.
 218    Only the array elements corresponding to blocked signals are relevant.  */
 219 static volatile handler_t old_handlers[NSIG];
 220 
 221 int
 222 sigprocmask (int operation, const sigset_t *set, sigset_t *old_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 223 {
 224   if (old_set != NULL)
 225     *old_set = blocked_set;
 226 
 227   if (set != NULL)
 228     {
 229       sigset_t new_blocked_set;
 230       sigset_t to_unblock;
 231       sigset_t to_block;
 232 
 233       switch (operation)
 234         {
 235         case SIG_BLOCK:
 236           new_blocked_set = blocked_set | *set;
 237           break;
 238         case SIG_SETMASK:
 239           new_blocked_set = *set;
 240           break;
 241         case SIG_UNBLOCK:
 242           new_blocked_set = blocked_set & ~*set;
 243           break;
 244         default:
 245           errno = EINVAL;
 246           return -1;
 247         }
 248       to_unblock = blocked_set & ~new_blocked_set;
 249       to_block = new_blocked_set & ~blocked_set;
 250 
 251       if (to_block != 0)
 252         {
 253           int sig;
 254 
 255           for (sig = 0; sig < NSIG; sig++)
 256             if ((to_block >> sig) & 1)
 257               {
 258                 pending_array[sig] = 0;
 259                 if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR)
 260                   blocked_set |= 1U << sig;
 261               }
 262         }
 263 
 264       if (to_unblock != 0)
 265         {
 266           sig_atomic_t received[NSIG];
 267           int sig;
 268 
 269           for (sig = 0; sig < NSIG; sig++)
 270             if ((to_unblock >> sig) & 1)
 271               {
 272                 if (signal (sig, old_handlers[sig]) != blocked_handler)
 273                   /* The application changed a signal handler while the signal
 274                      was blocked, bypassing our rpl_signal replacement.
 275                      We don't support this.  */
 276                   abort ();
 277                 received[sig] = pending_array[sig];
 278                 blocked_set &= ~(1U << sig);
 279                 pending_array[sig] = 0;
 280               }
 281             else
 282               received[sig] = 0;
 283 
 284           for (sig = 0; sig < NSIG; sig++)
 285             if (received[sig])
 286               raise (sig);
 287         }
 288     }
 289   return 0;
 290 }
 291 
 292 /* Install the handler FUNC for signal SIG, and return the previous
 293    handler.  */
 294 handler_t
 295 rpl_signal (int sig, handler_t handler)
     /* [previous][next][first][last][top][bottom][index][help] */
 296 {
 297   /* We must provide a wrapper, so that a user can query what handler
 298      they installed even if that signal is currently blocked.  */
 299   if (sig >= 0 && sig < NSIG && sig != SIGKILL && sig != SIGSTOP
 300       && handler != SIG_ERR)
 301     {
 302       #ifdef SIGABRT_COMPAT
 303       if (sig == SIGABRT_COMPAT)
 304         sig = SIGABRT;
 305       #endif
 306 
 307       if (blocked_set & (1U << sig))
 308         {
 309           /* POSIX states that sigprocmask and signal are both
 310              async-signal-safe.  This is not true of our
 311              implementation - there is a slight data race where an
 312              asynchronous interrupt on signal A can occur after we
 313              install blocked_handler but before we have updated
 314              old_handlers for signal B, such that handler A can see
 315              stale information if it calls signal(B).  Oh well -
 316              signal handlers really shouldn't try to manipulate the
 317              installed handlers of unrelated signals.  */
 318           handler_t result = old_handlers[sig];
 319           old_handlers[sig] = handler;
 320           return result;
 321         }
 322       else
 323         return signal (sig, handler);
 324     }
 325   else
 326     {
 327       errno = EINVAL;
 328       return SIG_ERR;
 329     }
 330 }
 331 
 332 #if GNULIB_defined_SIGPIPE
 333 /* Raise the signal SIGPIPE.  */
 334 int
 335 _gl_raise_SIGPIPE (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 336 {
 337   if (blocked_set & (1U << SIGPIPE))
 338     pending_array[SIGPIPE] = 1;
 339   else
 340     {
 341       handler_t handler = SIGPIPE_handler;
 342       if (handler == SIG_DFL)
 343         exit (128 + SIGPIPE);
 344       else if (handler != SIG_IGN)
 345         (*handler) (SIGPIPE);
 346     }
 347   return 0;
 348 }
 349 #endif

/* [previous][next][first][last][top][bottom][index][help] */