简体   繁体   English

当sighandler调用子例程时,perl信号处理仅工作一次

[英]perl signal processing only works once when sighandler calls subroutine

Setup: kernel: 4.1.16-v7+ OS: armv7l GNU/Linux (mostly debian) 设置:内核:4.1.16-v7 +操作系统:armv7l GNU / Linux(主要是debian)

This is perl 5, version 20, subversion 2 (v5.20.2) built for arm-linux-gnueabihf-thread-multi-64int

A larger perl code has a part of external process which sometimes does not respond within a certain timelimit. 较大的Perl代码具有外部过程的一部分,该过程有时在一定的时间限制内没有响应。 When this error occurs the "main" subroutine gets restarted via signal_handler command "restartservice" 发生此错误时,可通过signal_handler命令“ restartservice”重新启动“ main”子例程。

During debugging this issue i found numerous descriptions about signal handling and especially reinitialising a signal handler once you have used it. 在调试此问题期间,我发现了许多有关信号处理的描述,尤其是在使用后重新初始化信号处理程序。

and http://www.perlmonks.org/?node_id=440900 http://www.perlmonks.org/?node_id=440900

qouting: qouting:

Not all platforms automatically reinstall their (native) signal handlers >after a signal delivery. 并非所有平台>在信号传送后都会自动重新安装其(本机)信号处理程序。 This means that the handler works only the first >time the signal is sent. 这意味着处理程序仅在第一次发送信号时起作用。 The solution to this problem is to use "POSIX" >signal handlers if available, their behaviour is well-defined. 解决此问题的方法是使用“ POSIX”>信号处理程序(如果可用),它们的行为是明确定义的。

So i tried to figure out the POSIX way of doing it, did not found a solution until i reproduced the example from http://perldoc.perl.org/perlipc.html and enhanced it with my "restartservice" subroutine. 因此,我试图弄清楚POSIX的实现方式,直到从http://perldoc.perl.org/perlipc.html复制示例并通过“ restartservice”子例程对其进行了增强,才找到解决方案。

My issue seems to be: I cannot call an already defined subroutine when a signal_handler gets executed. 我的问题似乎是:当signal_handler被执行时,我无法调用已经定义的子例程。

Example: 例:

#!/usr/bin/perl
use warnings;
use strict;

sub restartservice()
{
    print "alarm reached\n";
    main();
};

sub main()
{
    while (1){
      print "while loop\n";
      eval {
        #local $SIG{ALRM} = sub { print "alarm main\n"; main();" };#fails
        local $SIG{ALRM} = sub { print "alarm main\n"; next; };#works
        #local $SIG{ALRM} = \&restartservice; #does not work ,proove below
        alarm 2;  
        sleep 5;# here i would use my normal code which sometimes hangs
        alarm 0;

      };
    };
}
main();

Output proove of working situation: 工作情况输出证明:

perl perlalarm.pl 
while loop
alarm main
Exiting subroutine via next at perlalarm.pl line 17.
Exiting eval via next at perlalarm.pl line 17.
while loop
alarm main
Exiting subroutine via next at perlalarm.pl line 17.
Exiting eval via next at perlalarm.pl line 17.
while loop
alarm main
...

Output proove of not working situation: 不工作情况的输出证明:

perl perlalarm.pl 
while loop
alarm reached
while loop
while loop
while loop

I would like to know what i have to do to get a subroutine working in that signal handler. 我想知道要在该信号处理程序中运行子例程该怎么办。

一旦在命名子例程中将main()替换为next main()使其等效于匿名子例程),它也将开始工作。

Generally, signals are masked when you are inside a signal handler, unless you set the SA_NODEFER flag through a sigaction call (in perl: POSIX::SigAction). 一般来说,当你是一个讯号处理器中的信号被屏蔽,除非你设置SA_NODEFER通过标志sigaction调用(在Perl:POSIX ::的sigaction)。

So, your second invocation of main() from within the signal handler runs main() with SIGALRM blocked. 因此,您从信号处理程序中对main()第二次调用在阻止SIGALRM的情况下运行main() Your execution looks like this: 您的执行如下所示:

time | No Signals Blocked | SIGALRM Blocked
-----+--------------------+------------------
  0  |   main()           |
  1  |    while ...       |
  2  |     eval {         |
  3  |      $SIG{ALRM}... |
 ... |     sleep          |
     |    <<ALARM>>       | $SIG{ALRM} invoked
  n  |                    | restartservice()
 n+1 |                    |  main()
 n+2 |                    |   while ...
 n+3 |                    |    ....
 n+4 |                    |  <<ALARM>>       # <-- blocked, no effect

Good practice is to do something very small and discrete in a signal handler, like set a flag or, sometimes, throw an exception. 优良作法是在信号处理程序中执行非常小的离散操作,例如设置标志或有时引发异常。 In perl, the eval{}+alarm idiom is usually the latter: 在perl中, eval{}+alarm惯用语通常是后者:

while (1) {
  my $ok = eval {
    local $SIG{ALRM} = sub { die "ALARM"; };
    alarm(5);
    do_something();
    alarm(0);
    1; # $ok
  };
  next if $ok;
  if ($@ =~ /ALARM/) {
    # timed out
  } else {
    # some other failure
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM