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.
If the process is woken up by deliver of a signal that invokes a handler
function, and the handler function returns, then
The mask remains set only as long as
sigsuspend is waiting.
sigsuspend always restores the previous signal mask
when it returns.
The return value and error conditions are the same as for
sigsuspend, you can replace the
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
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.
Go to the first, previous, next, last section, table of contents.