17

If no signal in set is pending at the time of the call, the thread shall be suspended until one or more becomes pending. The signals defined by set shall have been blocked at the time of the call to sigwait(); otherwise, the behavior is undefined. The effect of sigwait() on the signal actions for the signals in set is unspecified.

This is really ambiguous ,what's the difference between pending and block here?

And its conclusion on how to choose between sigwait and sigaction is not clear at all:

In summary, when it is necessary for code run in response to an asynchronous signal to notify a thread, sigwait() should be used to handle the signal. Alterna- tively, if the implementation provides semaphores, they also can be used, either following sigwait() or from within a signal handling routine previously registered with sigaction().

Can someone make the reason of sigwait more rational?

cpuer
  • 7,413
  • 14
  • 35
  • 39

2 Answers2

26

Every process has what's called a signal mask associated with it, which defines the set of signals which are blocked. The signal mask can be queried or set with setprocmask(2) (for single-threaded code) and pthread_sigmask(3) (for multithreaded code).

Whenever a signal is raised (either explicitly via kill(2) or raise(3), or via some other mechanism such as a segmentation fault raising SIGSEGV), the signal is checked against the current signal mask. If the signal is not blocked, then it is acted upon immediately: the corresponding signal handler is called if set, otherwise the default action (typically exiting with abnormal status or ignoring it) is run. If the signal is blocked by the signal mask, then the state of the signal is set to pending, and the program continues execution.

So consider the following example program:

#include <signal.h>
#include <stdio.h>

void on_sigusr1(int sig)
{
  // Note: Normally, it's not safe to call almost all library functions in a
  // signal handler, since the signal may have been received in a middle of a
  // call to that function.
  printf("SIGUSR1 received!\n");
}

int main(void)
{
  // Set a signal handler for SIGUSR1
  signal(SIGUSR1, &on_sigusr1);

  // At program startup, SIGUSR1 is neither blocked nor pending, so raising it
  // will call the signal handler
  raise(SIGUSR1);

  // Now let's block SIGUSR1
  sigset_t sigset;
  sigemptyset(&sigset);
  sigaddset(&sigset, SIGUSR1);
  sigprocmask(SIG_BLOCK, &sigset, NULL);

  // SIGUSR1 is now blocked, raising it will not call the signal handler
  printf("About to raise SIGUSR1\n");
  raise(SIGUSR1);
  printf("After raising SIGUSR1\n");

  // SIGUSR1 is now blocked and pending -- this call to sigwait will return
  // immediately
  int sig;
  int result = sigwait(&sigset, &sig);
  if(result == 0)
    printf("sigwait got signal: %d\n", sig);

  // SIGUSR1 is now no longer pending (but still blocked).  Raise it again and
  // unblock it
  raise(SIGUSR1);
  printf("About to unblock SIGUSR1\n");
  sigprocmask(SIG_UNBLOCK, &sigset, NULL);
  printf("Unblocked SIGUSR1\n");

  return 0;
}

Output:

SIGUSR1 received!
About to raise SIGUSR1
After raising SIGUSR1
sigwait got signal: 30
About to unblock SIGUSR1
SIGUSR1 received!
Unblocked SIGUSR1
Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
  • 1
    Actually every thread has a signal mask, not just every process, and `pthread_sigmask` is safe to use in any thread, but `sigprocmask` might misbehave if used in multithreaded programs. – R.. GitHub STOP HELPING ICE Jun 13 '11 at 05:33
  • @R.. ,I found another API `sigsuspend` which seems to have the same function as `sigwait`.... – cpuer Jun 13 '11 at 06:54
  • It seems that the big difference between the two is that `sigaction` provides a means by which signals are handled externally to any thread in the process (the signal catching function is not part of any thread's normal flow of execution). But `sigwait` provides a way for signals to be handled directly within one (or more) of the process's threads (the handling is done as part of the thread's normal flow of execution). This would mean that using `sigwait` puts fewer restrictions on the handling code. Using `sigaction` means the handling code is restricted to "signal safe" actions. Am I right? – Dan Moulding Mar 22 '13 at 03:13
4

From the signal(7) man page:

Signal Mask and Pending Signals
    A  signal  may  be  blocked,  which means that it will not be delivered
    until it is later unblocked.  Between the time when it is generated and
    when it is delivered a signal is said to be pending.

"Pending" and "blocked" are not mutually exclusive.

Also from the signal(7) man page:

Synchronously Accepting a Signal
    Rather than asynchronously catching a signal via a signal  handler,  it
    is  possible to synchronously accept the signal, that is, to block exe-
    cution until the signal is delivered, at which point the kernel returns
    information about the signal to the caller.  There are two general ways
    to do this:

    * sigwaitinfo(2), sigtimedwait(2),  and  sigwait(3)  suspend  execution
      until  one  of  the signals in a specified set is delivered.  Each of
      these calls returns information about the delivered signal.

So sigaction() is used to allow other code to run until a signal is pending, whereas sigwait() suspends execution of the thread until a signal is pending but blocked.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • `The signals defined by set shall have been blocked at the time of the call to sigwait();` how do we ensure that ,do we need to run additional code to ensure that,or automatically done inside sigwait? – cpuer Jun 13 '11 at 04:01
  • *Also* from the `signal(7)` man page: "Each thread in a process has an independent signal mask, which indicates the set of signals that the thread is currently blocking. A thread can manipulate its signal mask using pthread_sigmask(3). In a traditional single-threaded application, sigprocmask(2) can be used to manipulate the signal mask." – Ignacio Vazquez-Abrams Jun 13 '11 at 04:02
  • @cpuer: Yes, you must have blocked them with `sigprocmask` or equivalent. "Shall" is used to indicate requirements the standard places on the application programmer. – R.. GitHub STOP HELPING ICE Jun 13 '11 at 05:13
  • @Ignacio Vazquez-Abrams ,will it cause memory to be wasted if too many signals are blocked there? – cpuer Jun 13 '11 at 07:51
  • The mask exists whether or not the signals are blocked. If you're asking about pending signals being blocked then I couldn't tell you; I don't know the kernel's internal structures that well. – Ignacio Vazquez-Abrams Jun 13 '11 at 07:56
  • I'm not asking the exact structure of pending signals,just doubting whether memory will be eaten up quickly if signals continues being blocked there... – cpuer Jun 13 '11 at 08:23
  • Signals aren't supposed to be triggered that often; if they are, then you're deliberately doing something with them anyway and they won't build up. – Ignacio Vazquez-Abrams Jun 13 '11 at 08:24
  • How is it guaranteed that they won't build up? Is there any reference? – cpuer Jun 13 '11 at 08:32
  • Other than the code that has been written to deal with them? Not that I know of. – Ignacio Vazquez-Abrams Jun 13 '11 at 08:33
  • So you're sure the kernel code will guarantee the signals won't build up? – cpuer Jun 13 '11 at 08:52
  • Nope. But if you're deliberately doing something with the signals then you probably have a plan to deal with them. I mean, unless your program is insane. – Ignacio Vazquez-Abrams Jun 13 '11 at 08:54
  • @cpuer - Standard signals do not accumulate. Only one (per signal type) can be pending at any time. Any others of that type that are generated while one is pending are thrown away. It is different for realtime signals. They will be queued up to some system limit. Unfortunately in linux this limit and where to find it depends on what kernel version you are using. In any case, there *is* an upper limit imposed so the system is not going to signal itself out of memory resources and crash. – Duck Jun 13 '11 at 12:51
  • @Duck ,what's the difference between standard signals and realtime signals?Aren't they just numbers under the hood? – cpuer Jun 14 '11 at 01:21
  • The **Real-time Signals** section of the `signal(7)` man page talks about them. – Ignacio Vazquez-Abrams Jun 14 '11 at 01:27
  • Ok,so 32-63 is for rt signals.Are there any other categories of signals besides starndard and realtime signals? – cpuer Jun 14 '11 at 01:34
  • @cpuer - RT signals are SIGRTMIN + N up to SIGRTMAX. I forget but I think on linux SIGRTMIN is 34 or 36 because threads silently use a couple for internal reasons. It's just those two types and you won't run into RT under normal circumstances but if you do, they are queued. – Duck Jun 14 '11 at 03:43