Signals: Signal Handlers 431
From the program output, we can see that, after a longjmp() from the signal
handler, the signal mask remains set to the value to which it was set on entry to
the signal handler.
In the above shell session, we built the program using the makefile supplied
with the source code distribution for this book. The –s option tells make not to
echo the commands that it is executing. We use this option to avoid cluttering
the session log. ([Mecklenburg, 2005] provides a description of the GNU make
program.)
When we compile the same source file to build an executable that uses siglongjmp()
to exit the handler, we see the following:
$ make -s sigmask_siglongjmp Compiles using cc –DUSE_SIGSETJMP
$ ./sigmask_siglongjmp x
Signal mask at startup:
<empty signal set>
Calling sigsetjmp()
Type Control-C
Received signal 2 (Interrupt), signal mask is:
2 (Interrupt)
After jump from handler, signal mask is:
<empty signal set>
At this point, SIGINT is not blocked, because siglongjmp() restored the signal mask to
its original state. Next, we type Control-C again, so that the handler is once more
invoked:
Type Control-C
Received signal 2 (Interrupt), signal mask is:
2 (Interrupt)
After jump from handler, signal mask is:
<empty signal set>
Type Control-\ to kill the program
Quit
From the above output, we can see that siglongjmp() restores the signal mask to the
value it had at the time of the sigsetjmp() call (i.e., an empty signal set).
Listing 21-2 also demonstrates a useful technique for use with a signal handler
that performs a nonlocal goto. Because a signal can be generated at any time, it
may actually occur before the target of the goto has been set up by sigsetjmp() (or
setjmp()). To prevent this possibility (which would cause the handler to perform a
nonlocal goto using an uninitialized env buffer), we employ a guard variable,
canJump, to indicate whether the env buffer has been initialized. If canJump is false,
then instead of doing a nonlocal goto, the handler simply returns. An alternative
approach is to arrange the program code so that the call to sigsetjmp() (or setjmp())
occurs before the signal handler is established. However, in complex programs, it
may be difficult to ensure that these two steps are performed in that order, and the
use of a guard variable may be simpler.