Timeouts with eval / alarm pairs

Sometimes a syscall can block for a long time, whereas you want to give it a certain time before failing.

The solution is often to wrap the call in an eval{} block, using alarm to request that an alarm signal be sent to your script after the desired number of seconds, and set $SIG{ALRM} within the eval block's scope to die().

Easier illustrated than described:

 
eval {
    local $SIG{ALRM} = sub { die "alarm\n"; };
    alarm 5;  # time out after 5 seconds
 
    # do your syscall or whatever here
 
    alarm 0;  # if we reach here it completed before timeout,
              # so disable the alarm
};
 
# now check for errors:
if ($@) {
    # an error from the eval, let's see what:
    if ($@ eq "alarm\n") {
        # it was the timeout:
    } else {
        # it was some other unexpected failure... better
        # either handle it or propagate it:
        die $@;
    }
}

Warning: changed signal handling in 5.8.0

I've not experienced any trouble so far, but signal handling changed in Perl 5.8.0, which *may* cause problems:

(from http:search.cpan.org/~lbaxter/Sys-SigAction-0.06/lib/Sys/SigAction.pm ): > Prior to version 5.8.0 perl implemented 'unsafe' signal handling. The reason it is > considered unsafe, is that there is a risk that a signal will arrive, and be handled > while perl is changing internal data structures. This can result in all kinds of subtle > and not so subtle problems. For this reason it as always been recommended that one do > as little as possible in a signal handler, and only variables that already exist be > manipulated. > > Perl 5.8.0 and later versions implements 'safe' signal handling on platforms which > support the POSIX sigaction() function. This is accomplished by having perl note that > a signal has arrived, but deferring the execution of the signal handler until such time > as it is safe to do so. Unfortunately these changes can break some existing scripts, if > they depended on a system routine being interupted by the signal's arrival. The perl 5.8.0 > implementation was modified further in version 5.8.2. The Sys::SigAction CPAN module provides a relatively easy way to handle signals correctly, using the POSIX sigaction() function on Perl > 5.8.0, and an equivalent using eval{} and a code reference in $SIG{ALRM} for earlier versions, taking away the headaches. Two examples of using Sys::SigAction : <code perl> #timeout a system call: use Sys::SigAction qw( set_sig_handler ); eval { my $h = set_sig_handler( 'ALRM' ,\&mysubname ,{ mask⇒[ 'ALRM' ] ,safe⇒1 } ); alarm(2) ... do something you want to timeout alarm(0); }; #signal handler is reset when $h goes out of scope alarm(0); if ( $@ ) ... </code> or <code perl> use Sys::SigAction qw( timeout_call ); if ( timeout_call( 5 ,sub { $retval = DoSomething( @args ); } ) { print “DoSomething() timed out\n” ; } </code> ~~DISCUSSION~~

 
perl/timeoutalarm.txt · Last modified: 2010/02/26 10:45 (external edit)
 
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki