Perl signal handlers are reset in END blocks

点点圈 提交于 2020-01-13 14:15:08

问题


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 a die() 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!