For signals to be useful, they must be trapped and dealt with.
However, you shouldn't try to do too much when you
trap a signal. Generally, you should only generate a warning and deal
with the condition that caused the error. In a way,
Perl's %SIG keeps you from doing
too much. %SIG works like this:
$SIG{I_GOT_THIS_SIGNAL} = \&now_call_this_sub_to_handle_it;
sub now_call_this_sub_to_handle it {
...
}
If you need to know which signals Perl is aware of, do a
'kill -l' on a Unix system, or use
Config.pm:
#!/usr/local/bin/perl -w
use Config;
print "Perl knows about the following signals:\n";
print $Config{sig_name_init}, "\n";
Here's a simple snippet that lets you know if
someone sent you a HUP signal:
$SIG{HUP} = \&hic_hup;
sub hic_hup {
my $signal = shift;
# Don't die for now. Just warn us.
warn "Somebody sent me a SIG${signal}\n";
}
sub kill_handler {
local $SIG{KILL} = 'IGNORE'; # Inherited by all functions here
i_will_settle_for_denial();
}
sub i_will_settle_for_denial {
# KILL ignored for now. Go in peace.
}
Unix allows you to kill processes with negative process IDs by
sending a signal zero. If you have a program
that starts itself and several children, use 'kill
-PARENT_PID' to kill the parent and all of the children
processes. But obviously, if you send a HUP to the
parent, you don't want the parent to die. You can
avoid this with Perl and signals:
sub be_nice_to_your_parents {
local($SIG{HUP}) = 'IGNORE';
kill('HUP', -$$); # This pid and its kids
}
Naturally, you don't have to do anything fancy with
signal handlers. You can simply die if the given
$SIG{NAME} won't cause negative
effects on your system if you mishandle it:
$SIG{INT} = sub {
die "\nYou've interrupted me for one last time!\n"
};
Keep in mind that it's not all fun and games with
Perl and signals. If you don't know how your
system's C library and its signals implementation
behave, or if you haven't read the instructions
before firing your BB gun, you'll shoot your eye
out. We guarantee it!
As of Perl 5.8, you can probably be a little more confident in
Perl's ability to handle even a bad system-specific
signals implementation. In the old days, when men were men and
eyeless men were everywhere, a bad signals implementation at both a
system and Perl level, or a signal cropping up at the wrong time,
could corrupt Perl's internal state. Thankfully,
Perl 5.8 and later will postpone signal handling until
it's safe to proceed. This means that while the
signals interface doesn't change, even if your
program catches a signal at a specific place, Perl 5.8 and later will
finish whatever they are doing when the signal is encountered.
Finally, signals aren't limited to coping with the
behaviors of processes. You can also trap alarm signals for Perl
functions and system calls alike if your Perl code lives in an
eval( ) block. For example, let's
say you want to ping a host,
your-host.your.domain, and you want the ping
process to timeout in a reasonable amount of time if
your-host.your.domain isn't
available. You can use alarm( ) inside of
eval( ), like so:
#!/usr/local/bin/perl -w
my $to_ping = 'your-host.your.domain';
my $a_secs = 5;
eval {
local $SIG{ALRM} = sub { die "no dice for $to_ping" };
alarm $a_secs;
system("/usr/sbin/ping", $to_ping);
alarm 0;
};
if ($@ and $@ !~ /no dice for $to_ping/) { die }