MorgothSauron has asked for the wisdom of the Perl Monks concerning the following question:

Hi all, I'm developping a Perl script that do some system calls. Sometimes, these commands will block. I'm looking for a way to 'install' a timeout on these calls. I did some test using signals.
$TIMEOUT = 5; $CMD = $ARGV[0]; eval { $SIG{ALARM} = sub { die "TIMEOUT\n" }; alarm $TIMEOUT; system($CMD); alarm 0; }; # do error processing
I do receive the timeout message as expected. However, the command that was started is still running in the background. How to 'kill' the command if the timeout is reached ? If using 'fork', how can I get the output of my command ? I also need the output of the command. Any suggestion ? Thanks.

Replies are listed 'Best First'.
Re: Timeout on system command
by revdiablo (Prior) on Jul 06, 2004 at 20:22 UTC

    I recommend using a piping form of open, and capturing the returned PID. Then, in your signal handler, you can kill the PID, to ensure it goes away. Example:

    my $pid; eval { local $SIG{ALRM} = sub { die "TIMEOUT" }; alarm 2; $pid = open my $fh, "sleep 30|"; alarm 0; } if ($@ eq "TIMEOUT") { print "kill $pid\n"; kill 1, $pid; } elsif ($@) { die $@; }

    Take note that your example code had an error -- the key in %SIG should be ALRM and not ALARM.

    Update: apparently Joost posted essentially the same answer, but 10 minutes earlier than I did. Oh well, I guess that can be seen as validation of some sort.

    Update: fixed silly syntax error

Re: Timeout on system command
by Joost (Canon) on Jul 06, 2004 at 20:12 UTC
    system() doesn't give you the output of the executed command: it sends the output to STDOUT.

    You can probably* set ALARM, open P,"prog |"; read from P and close. There's lots of documentation and examples in perlipc and perlopentut.

    * there seem to be some issues with the safe signal handlers in recent perls. try it out.

    Joost.

    Update: The executed command will probably not end until it tries to write to its STDOUT, which is bound to the P file-handle in the pseudo-code above. You could try using kill to kill it immediately.

Re: Timeout on system command
by edan (Curate) on Jul 07, 2004 at 11:00 UTC

    You can find some example code I wrote in answer to somebody else who (it turned out after many iterations), had a very similar problem to solve.

    You'll find the following nodes helpful (I hope):

    The solution was about the same as some of the solutions already posted in this thread, but sometimes it helps to see a few different angles on it...

    Cheers.

    --
    edan

Re: Timeout on system command
by eyepopslikeamosquito (Archbishop) on Jul 07, 2004 at 09:06 UTC

    The general problem of timing out a slow event is discussed in the Perl Cookbook 2nd edition, Recipe 16.21 "Timing Out an Operation" and also in perlfaq8 "How do I timeout a slow event". On Unix, I suggest using $SIG{ALRM}/alarm (carefully). On Win2K and above, I recommend the Win32::Job module.

    See also Timing and timing out Unix commands and Timing Windows commands.