(root)/
grep-3.11/
gnulib-tests/
pthread_sigmask.c
       1  /* POSIX compatible signal blocking for threads.
       2     Copyright (C) 2011-2023 Free Software Foundation, Inc.
       3  
       4     This file is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU Lesser General Public License as
       6     published by the Free Software Foundation; either version 2.1 of the
       7     License, or (at your option) any later version.
       8  
       9     This file is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  #include <config.h>
      18  
      19  /* Specification.  */
      20  #include <signal.h>
      21  
      22  #include <errno.h>
      23  #include <stddef.h>
      24  
      25  #if PTHREAD_SIGMASK_INEFFECTIVE
      26  # include <string.h>
      27  #endif
      28  
      29  #if PTHREAD_SIGMASK_UNBLOCK_BUG
      30  # include <unistd.h>
      31  #endif
      32  
      33  int
      34  pthread_sigmask (int how, const sigset_t *new_mask, sigset_t *old_mask)
      35  #undef pthread_sigmask
      36  {
      37  #if HAVE_PTHREAD_SIGMASK
      38    int ret;
      39  
      40  # if PTHREAD_SIGMASK_INEFFECTIVE
      41    sigset_t omask, omask_copy;
      42    sigset_t *old_mask_ptr = &omask;
      43    sigemptyset (&omask);
      44    /* Add a signal unlikely to be blocked, so that OMASK_COPY
      45       is unlikely to match the actual mask.  */
      46    sigaddset (&omask, SIGILL);
      47    memcpy (&omask_copy, &omask, sizeof omask);
      48  # else
      49    sigset_t *old_mask_ptr = old_mask;
      50  # endif
      51  
      52    ret = pthread_sigmask (how, new_mask, old_mask_ptr);
      53  
      54  # if PTHREAD_SIGMASK_INEFFECTIVE
      55    if (ret == 0)
      56      {
      57        /* Detect whether pthread_sigmask is currently ineffective.
      58           Don't cache the information: libpthread.so could be dynamically
      59           loaded after the program started and after pthread_sigmask was
      60           called for the first time.  */
      61        if (memcmp (&omask_copy, &omask, sizeof omask) == 0
      62            && pthread_sigmask (1729, &omask_copy, NULL) == 0)
      63          {
      64            /* pthread_sigmask is currently ineffective.  The program is not
      65               linked to -lpthread.  So use sigprocmask instead.  */
      66            return (sigprocmask (how, new_mask, old_mask) < 0 ? errno : 0);
      67          }
      68  
      69        if (old_mask)
      70          memcpy (old_mask, &omask, sizeof omask);
      71      }
      72  # endif
      73  # if PTHREAD_SIGMASK_FAILS_WITH_ERRNO
      74    if (ret == -1)
      75      return errno;
      76  # endif
      77  # if PTHREAD_SIGMASK_UNBLOCK_BUG
      78    if (ret == 0
      79        && new_mask != NULL
      80        && (how == SIG_UNBLOCK || how == SIG_SETMASK))
      81      {
      82        /* Give the OS the opportunity to raise signals that were pending before
      83           the pthread_sigmask call and have now been unblocked.  */
      84        usleep (1);
      85      }
      86  # endif
      87    return ret;
      88  #else
      89    int ret = sigprocmask (how, new_mask, old_mask);
      90    return (ret < 0 ? errno : 0);
      91  #endif
      92  }