Explanation of sigsuspend needed
c, process, signals, unix
Solution
Major parts of the previous edition of this answer were wrong. I apologize for my mistake. I thank Wotim for pointing out the error.
POSIX's definition of `sigsuspend()`
The POSIX standard describes `sigsuspend()` fairly clearly:
`#include <signal.h>`
`int sigsuspend(const sigset_t *sigmask);`
DESCRIPTION
The `sigsuspend()` function shall replace the current signal mask of the calling thread with the set of signals pointed to by `sigmask` and then suspend the thread until delivery of a signal whose action is either to execute a signal-catching function or to terminate the process. This shall not cause any other signals that may have been pending on the process to become pending on the thread.
If the action is to terminate the process then `sigsuspend()` shall never return. If the action is to execute a signal-catching function, then `sigsuspend()` shall return after the signal-catching function returns, with the signal mask restored to the set that existed prior to the `sigsuspend()` call.
It is not possible to block signals that cannot be ignored. This is enforced by the system without causing an error to be indicated.
RETURN VALUE
Since `sigsuspend()` suspends thread execution indefinitely, there is no successful completion return value. If a return occurs, -1 shall be returned and errno set to indicate the error.
ERRORS
The `sigsuspend()` function shall fail if:
`[EINTR]` A signal is caught by the calling process and control is returned from the signal-catching function.
Also, the POSIX Signal concepts says:
Each thread has a "signal mask" that defines the set of signals currently blocked from delivery to it.
Application to your code fragments
The `sigsuspend()` function is the modern analogue of the old `pause()` function.
Major change: two code blocks reversed.
It allows you to send your thread to sleep until one of its selected signals occurs. If you want it to sleep until SIGRTMIN+1 arrives, you use:
sigfillset(&mask);
sigdelset(&mask, SIGRTMIN+1);
sigsuspend(&mask);
This blocks every signal except SIGRTMIN+1.
If you want to sleep until a signal other than SIGRTMIN+1 arrives, you use:
sigemptyset(&mask);
sigaddset(&mask, SIGRTMIN+1);
sigsuspend(&mask);
This blocks only SIGRTMIN+1.
Your loop won't print `Received signal` reliably unless you add a newline at the end (and maybe not even then; you might need to `fflush(stdout)` or equivalent). However, if you have SIGRTMIN+1 blocked in the ordinary course of events and then you set up `&oldmask` to allow only SIGRTMIN+1, then your signals will be reliably delivered while your code is in `sigsuspend()`.
Your description of `sigprocmask()` is not correct:
`sigprocmask` sets all signals in `mask+oldmask` to be blocked
When you do:
sigset_t mask, oldmask;
sigemptyset(&mask);
sigaddset(&mask, SIGRTMIN+1);
sigprocmask(SIG_BLOCK, &mask, &oldmask);
You add SIGRTMIN+1 to the list of blocked signals (because you used SIG_BLOCK and `mask` only contains SIGRTMIN+1). The output in `oldmask` is the signal mask before SIGRTMIN+1 was added. It might or might not already have contained SIGRTMIN+1. The process's signal mask is changed (if you needed to set the signal mask for a thread, you'd use `pthread_sigprocmask()` instead) from its current value to a new value containing SIGRTMIN+1, and you get told the old value.
From the comments
So is it wrong to use `sigsuspend(&oldmask)` as in my first example if I want to block SIGRTMIN+1?
Major change.
Yes, it is wrong. Calling `sigsuspend(&oldmask)` sends your thread to sleep until one of the signals in `oldmask` is received. The content of `oldmask` is the set of signals that was blocked before you added SIGRTMIN+1.
Yes, it is wrong. Calling `sigsuspend(&oldmask)` sends your thread to sleep until one of the signals not in `oldmask` is received. The content of `oldmask` is the set of signals that was blocked before you added SIGRTMIN+1.
The following two paragraphs are withdrawn rather than necessarily condemned as wrong. I think there are elements of truth in both, though there is room for improvement in both, too.
You do not use `sigsuspend()` to block signals per se; you use it to wait for one of a specified set of signals to arrive.
If you want to ignore SIGRTMIN+1, then you need to use `sigaction()` or you can use `sigprocmask()` as you did; that specifically blocks SIGRTMIN+1 as well as all the other signals that were already blocked.
Do I understand correctly that it will block the same signals the way it was?
Assuming 'it' is `sigsuspend()`, then it will block any signal not in `oldmask` and wait for one of the signals in `oldmask` to arrive.
Assuming 'it' is `sigsuspend()`, then it will block any signal in `oldmask` and wait for one of the signals not in `oldmask` to arrive.
And if I do `sigsuspend(&mask)` then it will block SIGRTMIN+1 and all of the signals in `oldmask` because of `sigprocmask(SIG_BLOCK, &mask, &oldmask)`?
Major change
Absolutely not! This will suspend the thread until one of the signals in `mask` arrives. Since the only signal in `mask` is SIGRTMIN+1, only when that arrives will `sigsuspend()` return. The `sigprocmask()` reported what was being blocked before the call in `oldmask`; it did not modify `mask` (your variable) at all; it did modify the process's signal mask by adding SIGRTMIN+1.
Absolutely not! This will suspend the thread until one of the signals not in `mask` arrives. Since the only signal in `mask` is SIGRTMIN+1, only that signal is blocked and when any other signal arrives, it will be handled and `sigsuspend()` will return. The `sigprocmask()` reported what was being blocked before the call in `oldmask`; it did not modify `mask` (your variable) at all; it did modify the process's signal mask by adding SIGRTMIN+1.
I strongly recommend reading, or rereading, the POSIX Signal concepts and the various functions that manipulate signal handling. (And yes, this is, in part, a prescription of "Physician, heal thyself".)
Please let me know if there are still mistakes in here.
Problem
I need a clarification on sigsuspend topic. I have a simplified example ``` sigset_t mask, oldmask; sigemptyset (&mask); sigaddset (&mask, SIGRTMIN+1); sigprocmask (SIG_BLOCK, &mask, &oldmask); sigsuspend(&oldmask); sigprocmask (SIG_UNBLOCK, &mask, NULL); ``` Here is how I understand this: - sigemptyset clears a list of signals (mask) - because it is initialized with currently blocked signals (?) - sigaddset adds SIGRTMIN+1 to mask - sigprocmask sets all signals in mask+oldmask to be blocked - sigsuspend(&oldmask) suspends thread execution till one of the blocked signals arrives ? Shouldn't there be sigsuspend(&mask) if I want to block SIGRTMIN+1? Secondly, let's suppose I have such sigsuspend in a loop and there arrived a few SIGRTMIN+1 signals. Will such loop continue for each signal ? in some kind of queue? ``` while(1){ sigsuspend(&oldmask) printf("recieved signal"); } ``` so that for each signal I have 'recieved signal' printed?