alarm Escaping Perl 'eval' block

↘锁芯ラ 提交于 2019-12-06 13:37:32

问题


I have a Perl script that automatically downloads content from various sources. It does the downloading in an eval block with an alarm so that the attempt will time out if it takes too long:

eval {
    alarm(5);
    my $res = $ua->request($req);
    $status = $res->is_success;
    $rawContent = $res->content;    
    $httpCode = $res->code;
    alarm(0);       
};

This has worked for years, but after doing some system updates, all of a sudden it quit working. Instead, the first source it hits that times out, I get the following error and the program terminates:

 Alarm clock

What am I doing incorrectly that is preventing eval from catching the alarm all of a sudden?


回答1:


The default for SIGALRM is to terminate the program, so you need to handle it. A common way is to issue a die when SIGALRM is caught, turning it into an exception, which is eval-ed.

eval {
    local $SIG{ALRM} = sub { die "Timed out" };
    alarm(5);
    my $res = $ua->request($req);
    $status = $res->is_success;
    $rawContent = $res->content;    
    $httpCode = $res->code;
    alarm(0);       
};
if ($@ and $@ !~ /Timed out/) { die }  # re-raise if it is other error

From Signals in perlipc

Signal handling is also used for timeouts in Unix, While safely protected within an eval{} block, you set a signal handler to trap alarm signals and then schedule to have one delivered to you in some number of seconds. Then try your blocking operation, clearing the alarm when it’s done but not before you’ve exited your eval{} block. If it goes off, you’ll use die() to jump out of the block, much as you might using longjmp() or throw() in other languages.


As for how it ever worked, the one thing I can think of is that packages used inside eval had their own timers, based on alarm, thus canceling your alarm. From alarm

Only one timer may be counting at once. Each call disables the previous timer, and an argument of 0 may be supplied to cancel the previous timer without starting a new one.

They may have thrown exceptions when timing out and you had the expected behavior. This package behavior changed in the update and now your alarm works and needs handling. This is a guess, of course.



来源:https://stackoverflow.com/questions/37817109/alarm-escaping-perl-eval-block

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