1  /* Implementation of sigwait function from POSIX.1c.
       2     Copyright (C) 1996-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library 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 GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <errno.h>
      20  #include <signal.h>
      21  #include <stddef.h>		/* For NULL.  */
      22  #include <sysdep-cancel.h>
      23  
      24  /* This is our dummy signal handler we use here.  */
      25  static void ignore_signal (int sig);
      26  
      27  /* Place where to remember which signal we got.  Please note that this
      28     implementation cannot be used for the threaded libc.  The
      29     libpthread must provide an own version.  */
      30  static int was_sig;
      31  
      32  
      33  static int
      34  do_sigwait (const sigset_t *set, int *sig)
      35  {
      36    sigset_t tmp_mask;
      37    struct sigaction saved[NSIG];
      38    struct sigaction action;
      39    int save_errno;
      40    int this;
      41  
      42    /* Prepare set.  */
      43    __sigfillset (&tmp_mask);
      44  
      45    /* Unblock all signals in the SET and register our nice handler.  */
      46    action.sa_handler = ignore_signal;
      47    action.sa_flags = 0;
      48    __sigfillset (&action.sa_mask);	/* Block all signals for handler.  */
      49  
      50    /* Make sure we recognize error conditions by setting WAS_SIG to a
      51       value which does not describe a legal signal number.  */
      52    was_sig = -1;
      53  
      54    for (this = 1; this < NSIG; ++this)
      55      if (__sigismember (set, this))
      56        {
      57  	/* Unblock this signal.  */
      58  	__sigdelset (&tmp_mask, this);
      59  
      60  	/* Register temporary action handler.  */
      61  	if (__sigaction (this, &action, &saved[this]) != 0)
      62  	  goto restore_handler;
      63        }
      64  
      65    /* Now we can wait for signals.  */
      66    __sigsuspend (&tmp_mask);
      67  
      68   restore_handler:
      69    save_errno = errno;
      70  
      71    while (--this >= 1)
      72      if (__sigismember (set, this))
      73        /* We ignore errors here since we must restore all handlers.  */
      74        __sigaction (this, &saved[this], NULL);
      75  
      76    __set_errno (save_errno);
      77  
      78    /* Store the result and return.  */
      79    *sig = was_sig;
      80    return was_sig == -1 ? -1 : 0;
      81  }
      82  
      83  
      84  int
      85  __sigwait (const sigset_t *set, int *sig)
      86  {
      87    /* __sigsuspend should be a cancellation point.  */
      88    return do_sigitid (idtype, id, infop, options);
      89  }
      90  libc_hidden_def (__sigwait)
      91  weak_alias (__sigwait, sigwait)
      92  
      93  
      94  static void
      95  ignore_signal (int sig)
      96  {
      97    /* Remember the signal.  */
      98    was_sig = sig;
      99  }