Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ways to do timeouts in Perl?

Tags:

timeout

perl

I frequently use the following pattern to set an upper bound to the running time of a particular code fragment in Perl:

my $TIMEOUT_IN_SECONDS = 5;
eval {
    local $SIG{ALRM} = sub { die "alarm\n" };
    alarm($TIMEOUT_IN_SECONDS);
    # do stuff that might timeout.
    alarm(0);
};
if ($@) {
    # handle timeout condition.
}

My questions:

  • Is this the right way to do it?
  • Are there any circumstances under which the running time can exceed $TIMEOUT_IN_SECONDS, or is the above method bullet-proof?
like image 694
knorv Avatar asked Mar 11 '10 07:03

knorv


3 Answers

You probably want to look at Sys::SigAction. I haven't used it myself, but it has some glowing reviews.

One thing to watch out for is if "stuff that might timeout" uses sleep or alarm itself. Also, in the error handling code, I assume you're prepared for errors other than a timeout.

like image 181
cjm Avatar answered Nov 11 '22 13:11

cjm


You could also try Time::Out. I like the syntax and nested timeouts are supported..

like image 37
Peter V. Mørch Avatar answered Nov 11 '22 11:11

Peter V. Mørch


Take care with signal handling. Perl receives signals asynchronously and they may be lost or interfere with each other if a signal is received while another signal is being handled by the callback.

Event-handling libraries' Win32 support is pretty so-so in Perl (I have to support non-cygwin Win32), so I generally use a simple polling loop for timeouts:

use Time::HiRes qw(sleep);

sub timeout {
  my $timeout = shift;
  my $poll_interval = shift;
  my $test_condition = shift;
  until ($test_condition->() || $timeout <= 0) {
    $timeout -= $poll_interval;
    sleep $poll_interval;
  }
  return $timeout > 0; # condition was met before timeout
}

my $success = timeout(30, 0.1, \&some_condition_is_met);

The sleep timer can be easily made user- or caller-configurable and unless you are doing an extremely tight loop or have multiple callers waiting on the loop (where you can end up with a race or dead lock), it is a simple, reliable, and cross-platform way to implement a timeout.

Also note that the loop overhead will mean that you cannot guarantee that the timeout is observed absolutely. $test_condition, the decrement, garbage collection, etc. can interfere.

like image 2
Jeff Ober Avatar answered Nov 11 '22 11:11

Jeff Ober