- publishing free software manuals
Perl Language Reference Manual
by Larry Wall and others
Paperback (6"x9"), 724 pages
ISBN 9781906966027
RRP £29.95 ($39.95)

Sales of this book support The Perl Foundation! Get a printed copy>>>

20.2.1 Deferred Signals (Safe Signals)

In Perls before Perl 5.7.3 by installing Perl code to deal with signals, you were exposing yourself to danger from two things. First, few system library functions are re-entrant. If the signal interrupts while Perl is executing one function (like malloc(3) or printf(3)), and your signal handler then calls the same function again, you could get unpredictable behavior--often, a core dump. Second, Perl isn't itself re-entrant at the lowest levels. If the signal interrupts Perl while Perl is changing its own internal data structures, similarly unpredictable behaviour may result.

There were two things you could do, knowing this: be paranoid or be pragmatic. The paranoid approach was to do as little as possible in your signal handler. Set an existing integer variable that already has a value, and return. This doesn't help you if you're in a slow system call, which will just restart. That means you have to die to longjmp(3) out of the handler. Even this is a little cavalier for the true paranoiac, who avoids die in a handler because the system is out to get you. The pragmatic approach was to say "I know the risks, but prefer the convenience", and to do anything you wanted in your signal handler, and be prepared to clean up core dumps now and again.

Perl 5.7.3 and later avoid these problems by "deferring" signals. That is, when the signal is delivered to the process by the system (to the C code that implements Perl) a flag is set, and the handler returns immediately. Then at strategic "safe" points in the Perl interpreter (e.g. when it is about to execute a new opcode) the flags are checked and the Perl level handler from %SIG is executed. The "deferred" scheme allows much more flexibility in the coding of signal handler as we know Perl interpreter is in a safe state, and that we are not in a system library function when the handler is called. However the implementation does differ from previous Perls in the following ways:

Long-running opcodes
As the Perl interpreter only looks at the signal flags when it is about to execute a new opcode, a signal that arrives during a long-running opcode (e.g. a regular expression operation on a very large string) will not be seen until the current opcode completes. N.B. If a signal of any given type fires multiple times during an opcode (such as from a fine-grained timer), the handler for that signal will only be called once after the opcode completes, and all the other instances will be discarded. Furthermore, if your system's signal queue gets flooded to the point that there are signals that have been raised but not yet caught (and thus not deferred) at the time an opcode completes, those signals may well be caught and deferred during subsequent opcodes, with sometimes surprising results. For example, you may see alarms delivered even after calling alarm(0) as the latter stops the raising of alarms but does not cancel the delivery of alarms raised but not yet caught. Do not depend on the behaviors described in this paragraph as they are side effects of the current implementation and may change in future versions of Perl.
Interrupting IO
When a signal is delivered (e.g. INT control-C) the operating system breaks into IO operations like read (used to implement Perls <> operator). On older Perls the handler was called immediately (and as read is not "unsafe" this worked well). With the "deferred" scheme the handler is not called immediately, and if Perl is using system's stdio library that library may re-start the read without returning to Perl and giving it a chance to call the %SIG handler. If this happens on your system the solution is to use :perlio layer to do IO - at least on those handles which you want to be able to break into with signals. (The :perlio layer checks the signal flags and calls %SIG handlers before resuming IO operation.) Note that the default in Perl 5.7.3 and later is to automatically use the :perlio layer. Note that some networking library functions like gethostbyname() are known to have their own implementations of timeouts which may conflict with your timeouts. If you are having problems with such functions, you can try using the POSIX sigaction() function, which bypasses the Perl safe signals (note that this means subjecting yourself to possible memory corruption, as described above). Instead of setting $SIG{ALRM}:
local $SIG{ALRM} = sub { die "alarm" };
try something like the following:
use POSIX qw(SIGALRM);
POSIX::sigaction(SIGALRM,
                 POSIX::SigAction->new(sub { die "alarm" }))
      or die "Error setting SIGALRM handler: $!\n";
Another way to disable the safe signal behavior locally is to use the Perl::Unsafe::Signals module from CPAN (which will affect all signals).
Restartable system calls
On systems that supported it, older versions of Perl used the SA_RESTART flag when installing %SIG handlers. This meant that restartable system calls would continue rather than returning when a signal arrived. In order to deliver deferred signals promptly, Perl 5.7.3 and later do not use SA_RESTART. Consequently, restartable system calls can fail (with $! set to EINTR) in places where they previously would have succeeded. Note that the default :perlio layer will retry read, write and close as described above and that interrupted wait and waitpid calls will always be retried.
Signals as "faults"
Certain signals, e.g. SEGV, ILL, and BUS, are generated as a result of virtual memory or other "faults". These are normally fatal and there is little a Perl-level handler can do with them, so Perl now delivers them immediately rather than attempting to defer them.
Signals triggered by operating system state
On some operating systems certain signal handlers are supposed to "do something" before returning. One example can be CHLD or CLD which indicates a child process has completed. On some operating systems the signal handler is expected to wait for the completed child process. On such systems the deferred signal scheme will not work for those signals (it does not do the wait). Again the failure will look like a loop as the operating system will re-issue the signal as there are un-waited-for completed child processes.

If you want the old signal behaviour back regardless of possible memory corruption, set the environment variable PERL_SIGNALS to "unsafe" (a new feature since Perl 5.8.1).

ISBN 9781906966027Perl Language Reference ManualSee the print edition