A
Anno Siegel
It is common practice to localize %SIG handlers in this fashion:
$SIG{ HUP} = \ &global_handler;
{
local $SIG{ HUP} = \ &local_handler;
# provoke and deal with one or more HUP signals
}
The assumption is that $SIG{ HUP} is either the global or the local
handler at all times, so the (HUP) signal will always be caught, but
apparently that assumption isn't true. "local" sets the handler
to undef, and then "=" sets it to \ &local_handler. It is quite
possible for a signal to arrive when the hander is undefined, which
ends the program through an uncaught signal. The following code
shows this:
my ( $count_a, $count_b) = ( 0, 0); # unused, but left in place
$SIG{ HUP} = sub { $count_a ++ };
# create a stream of HUP signals from kid to parent
my $parent = $$;
defined( my $pid = fork ) or die "fork: $!";
unless ( $pid ) {
require Time::HiRes;
require POSIX;
my $tick = 1/POSIX::sysconf( POSIX::_SC_CLK_TCK());
while ( 1 ) {
kill HUP => $parent or exit; # don't survive parent
Time::HiRes::sleep( $tick); # shortest admissible sleep time
}
exit(); # not reached;
}
# main loop
while ( 1 ) {
{
local $SIG{ HUP} = sub { $count_b ++ };
# my $save = $SIG{ HUP};
# $SIG{ HUP} = sub { $count_b ++ };
# $SIG{ HUP} = $save;
}
}
With the "main loop" as shown ("local" active), after a few seconds
the program ends with a "Hangup" message, characteristic for an
uncaught HUP signal. With "local" commented out and the other three
lines active, the program runs happily as long as I let it.
My conclusion: The practice of localizing %SIG handlers isn't safe,
and probably never has been.
Comments?
Anno
$SIG{ HUP} = \ &global_handler;
{
local $SIG{ HUP} = \ &local_handler;
# provoke and deal with one or more HUP signals
}
The assumption is that $SIG{ HUP} is either the global or the local
handler at all times, so the (HUP) signal will always be caught, but
apparently that assumption isn't true. "local" sets the handler
to undef, and then "=" sets it to \ &local_handler. It is quite
possible for a signal to arrive when the hander is undefined, which
ends the program through an uncaught signal. The following code
shows this:
my ( $count_a, $count_b) = ( 0, 0); # unused, but left in place
$SIG{ HUP} = sub { $count_a ++ };
# create a stream of HUP signals from kid to parent
my $parent = $$;
defined( my $pid = fork ) or die "fork: $!";
unless ( $pid ) {
require Time::HiRes;
require POSIX;
my $tick = 1/POSIX::sysconf( POSIX::_SC_CLK_TCK());
while ( 1 ) {
kill HUP => $parent or exit; # don't survive parent
Time::HiRes::sleep( $tick); # shortest admissible sleep time
}
exit(); # not reached;
}
# main loop
while ( 1 ) {
{
local $SIG{ HUP} = sub { $count_b ++ };
# my $save = $SIG{ HUP};
# $SIG{ HUP} = sub { $count_b ++ };
# $SIG{ HUP} = $save;
}
}
With the "main loop" as shown ("local" active), after a few seconds
the program ends with a "Hangup" message, characteristic for an
uncaught HUP signal. With "local" commented out and the other three
lines active, the program runs happily as long as I let it.
My conclusion: The practice of localizing %SIG handlers isn't safe,
and probably never has been.
Comments?
Anno