Using `sigsuspend'
------------------
The clean and reliable way to wait for a signal to arrive is to
block it and then use `sigsuspend'. By using `sigsuspend' in a loop,
you can wait for certain kinds of signals, while letting other kinds of
signals be handled by their handlers.
- Function: int sigsuspend (const sigset_t *SET)
This function replaces the process's signal mask with SET and then
suspends the process until a signal is delivered whose action is
either to terminate the process or invoke a signal handling
function. In other words, the program is effectively suspended
until one of the signals that is not a member of SET arrives.
If the process is woken up by delivery of a signal that invokes a
handler function, and the handler function returns, then
`sigsuspend' also returns.
The mask remains SET only as long as `sigsuspend' is waiting. The
function `sigsuspend' always restores the previous signal mask
when it returns.
The return value and error conditions are the same as for `pause'.
With `sigsuspend', you can replace the `pause' or `sleep' loop in
the previous section with something completely reliable:
sigset_t mask, oldmask;
...
/* Set up the mask of signals to temporarily block. */
sigemptyset (&mask);
sigaddset (&mask, SIGUSR1);
...
/* Wait for a signal to arrive. */
sigprocmask (SIG_BLOCK, &mask, &oldmask);
while (!usr_interrupt)
sigsuspend (&oldmask);
sigprocmask (SIG_UNBLOCK, &mask, NULL);
This last piece of code is a little tricky. The key point to
remember here is that when `sigsuspend' returns, it resets the process's
signal mask to the original value, the value from before the call to
`sigsuspend'--in this case, the `SIGUSR1' signal is once again blocked.
The second call to `sigprocmask' is necessary to explicitly unblock
this signal.
One other point: you may be wondering why the `while' loop is
necessary at all, since the program is apparently only waiting for one
`SIGUSR1' signal. The answer is that the mask passed to `sigsuspend'
permits the process to be woken up by the delivery of other kinds of
signals, as well--for example, job control signals. If the process is
woken up by a signal that doesn't set `usr_interrupt', it just suspends
itself again until the "right" kind of signal eventually arrives.
This technique takes a few more lines of preparation, but that is
needed just once for each kind of wait criterion you want to use. The
code that actually waits is just four lines.