16.17. Writing a Signal HandlerProblemYou want to write a subroutine that will be called whenever your program receives a signal. SolutionA signal handler is just a subroutine. With some risk, you can do anything in a signal handler you'd do in any Perl subroutine, but the more you do, the riskier it gets. Some systems require you to reinstall your signal handler after each signal: $SIG{INT} = \&got_int; sub got_int { $SIG{INT} = \&got_int; # but not for SIGCHLD! # ... }
Some systems restart blocking operations, such as reading data. In such cases, you must call my $interrupted = 0; sub got_int { $interrupted = 1; $SIG{INT} = 'DEFAULT'; # or 'IGNORE' die; } eval { $SIG{INT} = \&got_int; # ... long-running code that you don't want to restart }; if ($interrupted) { # deal with the signal } DiscussionInstalling a custom signal handling subroutine is a lot like playing with fire. It may seem like a lot of fun, but, sooner or later, you're going to get burned unless you're exceedingly careful. By installing Perl code to deal with signals, you're exposing yourself to two dangers. 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. (Release 5.005 of Perl supports lightweight processes called threads .) If the signal interrupts Perl while Perl is changing its own internal data structures, unpredictable behavior may result - usually random core dumps.
You have two options: be paranoid or be pragmatic. The paranoid approach is to do as little as possible in your signal handler, as exemplified by the
Signals have been implemented in many different operating systems, often in slightly different flavors. The two situations where signal implementations vary the most are when a signal occurs when its signal handler is active (
reliability
), and when a signal interrupts a blocking system call like The initial implementation of signals was unreliable, meaning that while a handler was running, further occurrences of the same signal would cause the default action, likely aborting the program. Later systems addressed this (each in their own subtly different way, of course) by providing a way to block the delivery of further signals of that number until the handler has finished. If Perl detects that your system can use reliable signals, it generates the proper system calls to achieve this saner, safer behavior. You can use POSIX signals to block signal delivery at other times, as described in Recipe 16.20 . For truly portable code, the paranoid programmer will assume the worst case (unreliable signals) and reinstall the signal handler manually, usually as the first statement in a function: $SIG{INT} = \&catcher; sub catcher { $SIG{INT} = \&catcher; # ... } In the special case of catching SIGCHLD, see Recipe 16.19 . System V has bizarre behavior that can trip you up. Use the Config module to find out whether you have reliable signals: use Config; print "Hurrah!\n" if $Config{d_sigaction}; Just because you have reliable signals doesn't mean you automatically get reliable programs. But without them, you certainly won't.
The first implementation of signals interrupted slow system calls, functions that require the cooperation of other processes or device drivers. If a signal comes in while those system calls are still running, they (and their Perl counterparts) return an error value and set the error to EINTR, To determine whether your interrupted system calls will automatically restart, look at your system's C signal.h include file: % egrep 'S[AV]_(RESTART|INTERRUPT)' /usr/include/*/signal.h Two signals are untrappable and unignorable: SIGKILL and SIGSTOP. Full details of the signals available on your system and what they mean can be found in the signal (3) manpage. See AlsoThe "Signals" sections in Chapter 6 of Programming Perl and in perlipc (1); your system's sigaction (2), signal (3), and kill (2) manpages (if you have them). Porting UNIX Software , by Greg Lehey, O'Reilly & Associates, (1995); Advanced Programming in the Unix Environment |
|