Timothy R. Butler Timothy R. Butler - 5 months ago 17
Perl Question

Exception Escaping Perl 'eval' block

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?

Answer

You need to handle $SIG{ALRM} to make it die, turning it into exception.

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);       
};

The default for SIGALRM is to terminate the program so we need a handler. 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.