问题
This works as expected since Perl 5.10.1: SIGINTs are trapped.
#!/usr/bin/perl
use strict;
use warnings;
$SIG{INT} = sub { die "Caught a sigint $!" };
sleep(20);
But here SIGINTs are not trapped.
#!/usr/bin/perl
use strict;
use warnings;
$SIG{INT} = sub { die "Caught a sigint $!" };
END {
sleep(20);
}
This can be fixed by setting the handler again in the END
block, like so:
END {
$SIG{INT} = sub { die "Caught a sigint $!" };
sleep(20);
}
But that won't work if you have more than one block: handlers must be set again for every block.
I've tried to figure this out and I can't find an explanation at perldoc. The only mention of this behaviour I can find is a footnote from Practical Perl Programming A D Marshall 1999-2005
Note Signals that are sent to your script can bypass the END blocks.
Would someone explain this?
回答1:
This works for me: Re-install the handler in the END block that runs first (last in code).
use warnings;
use strict;
use feature 'say';
$SIG{INT} = sub { say "SIGINT: got zap!" };
#sleep 10;
say "done";
END { say "END, runs last" }
END { say "END, runs next to last. Sleep then print"; sleep 10; say "Woke up."; }
# Executed first in END phase. The sole purpose: to reinstall the handler
END {
$SIG{INT} = sub { say "SIGINT in END block, got zap" };
}
When started and Ctrl-C-ed after a few seconds this prints
done. END, runs next to last. Sleep then print ^CSIGINT in END block, got zap Woke up. END, runs last
So you need to add an END
block, last in the code, END { $SIG{INT} = 'IGNORE' }
.
It appears that the change to "END" ${^GLOBAL_PHASE}
removes or otherwise disables the handler.
But once the handler is re-installed in the END
phase it is effective throughout. It's cleanest of course to do that in the END
block that is executed first.
I will update when (if) I understand more detail and find documentation on this behavior.
回答2:
perldoc perlmod says:
An "END" code block is executed as late as possible, that is, after
perl
has finished running the program and just before the interpreter is being exited, even if it is exiting as a result of adie()
function. (But not if it's morphing into another program via "exec
", or being blown out of the water by a signal--you have to trap that yourself (if you can).)
I expect signal handlers to have been removed just before the interpreter is being exited. Therefore, I am not quite able to see what is surprising or unanticipated.
来源:https://stackoverflow.com/questions/40688429/perl-signal-handlers-are-reset-in-end-blocks