in reply to Cannot catch ALRM signal for timeout

...so that if the worker takes too long

What exactly is taking too long? I.e., does the worker program stop delivering output, so that the $str = <WORKER> blocks, or does it just keep outputting lines for too long?  In the latter case, I wouldn't expect the alarm to work, because the alarm is always being reset immediately after the read (which takes almost no time if it succeeds)...

An alternative to the alarm approach would be to fork and have the child kill the external process after a while.  (I'll post an example later (unless someone else has already done so by then) — it's lunch-time here...)

Replies are listed 'Best First'.
Re^2: Cannot catch ALRM signal for timeout
by almut (Canon) on Dec 08, 2009 at 15:17 UTC

    FWIW, here's the promised example, i.e. the alternative approach using a separate "watch" process to handle the killing:

    #!/usr/bin/perl sub run_with_timeout { my ($cmd, $timeout, $outref) = @_; my $rc = -1; # return code in case of timeout if (my $pid = open(my $pipe, "-|")) { my $pid2 = fork(); die "cannot fork" unless defined $pid; if ($pid2) { @$outref = <$pipe>; close $pipe; # does an implicit wait, returns status + in $? my $normalexit = ($? & 0x7f)==0; $rc = $? >> 8 if $normalexit; kill 'INT', $pid2 if $normalexit; # watcher no longer nee +ded (cmd finished) wait; return $rc; } else { select undef,undef,undef,$timeout; kill 'INT', $pid; # kill command if still there exit; } } else { exec "exec $cmd 2>&1"; # exec, so $cmd runs under $pid } } my $cmd = <<'EOCMD'; perl -e ' $|=1; my $t=0.2; for (0..10) { printf "%.1f\n", $_*$t; select undef,undef,undef, $t; } exit 42;'; EOCMD my $timeout = 1.5; my $output = []; my $ret = run_with_timeout($cmd, $timeout, $output); printf "return code: %d%s\n", $ret, $ret == -1 ? ' (timed out)':''; print "output of command:\n",@$output; __END__ return code: -1 (timed out) output of command: 0.0 0.2 0.4 0.6 0.8 1.0 1.2 1.4
Re^2: Cannot catch ALRM signal for timeout
by Magice (Novice) on Dec 08, 2009 at 13:01 UTC
    By "taking too long", I mean if the worker stops delivering output. My idea is to wait for the output of the worker, and if the worker does not write/print anything in a while, then reset it. Thank you!