http://www.perlmonks.org?node_id=206612

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

Hi,

I have coded a script that loops over MP3's in a given directory. The script runs an external command, mp3_check on each file with IPC::Open3, parses it's output, then adds the data to an Oracle table with DBI/DBD.

The problem with this is the mp3_check command sometimes hangs on problem files. What I would like to do is setup a timer of some sort then run the command. If the child process doesn't complete before the timer expires, I'd like to kill the process and continue with the loop over the files.

Here is the code I've got now to call the external program and gather it's output:

use IPC::Open3; my $pid = open3(*IN, *OUT, *ERR, $command); waitpid $pid, 0; close(IN); my @outlines = <OUT>;


Could anyone give me ideas as to how to setup a timer of say 5 seconds on this, then kill it if the timer expires?

Thanks,
Cameron

Replies are listed 'Best First'.
Re: Timing External Program Execution
by tadman (Prior) on Oct 20, 2002 at 04:27 UTC
    This is done with the signal handler for the alarm call:
    use warnings; use strict; my $fuse = 10; # Seconds foreach (<*.mp3>) { print "$_\n"; # Update on progress # If the fork() produces a process... if (my $pid = fork()) { # ...wait for it to finish. wait(); } else { # This causes the process to exit on # an alarm call. $SIG{ALRM} = sub { exit(); }; # This sets the timer on the alarm alarm($fuse); # This runs a command that takes a long # time and has to be stopped early. system("/bin/sleep 10000"); # Important to exit() here or you'll # keep going through the loop creating # more processes! exit(); } }
      ...very nicely coded example. Thank you. (++)

      ...All the world looks like -well- all the world, when your hammer is Perl.
      ---v

Re: Timing External Program Execution
by Zaxo (Archbishop) on Oct 20, 2002 at 03:21 UTC

    If you call core four arg select or use IO::Select to read the output, you can specify a timeout as the fourth argument. The need to use fileno-based bitmaps in the select call is not pretty, but worth it.

    After Compline,
    Zaxo

Re: Timing External Program Execution
by Aristotle (Chancellor) on Oct 20, 2002 at 02:31 UTC
    What you want to look into is the alarm function. I don't have any actual experience with it, so someone else would have to supply sample code, since there are a couple gotchas to it.

    Makeshifts last the longest.

      alarm does not work on Windows. At least, not on the non-NT flavours I have access to.

      Update (26 oct): I just saw this journal entry on use.perl, with a link to an Perl script using an alternative approach (for Win32 only). It loks very much applicable to this particular problem.

Re: Timing External Program Execution
by IlyaM (Parson) on Oct 20, 2002 at 15:03 UTC
    Probably the easiest solution is using IPC::Run.

    Example from this module docs:

    use IPC::Run qw( run timeout ); run \@cmd, \$in, \$out, \$err, timeout( 10 ) or die "cat: $?"

    --
    Ilya Martynov, ilya@iponweb.net
    CTO IPonWEB (UK) Ltd
    Quality Perl Programming and Unix Support UK managed @ offshore prices - http://www.iponweb.net
    Personal website - http://martynov.org

Re: Timing External Program Execution
by Anonymous Monk on Oct 22, 2002 at 16:41 UTC
    You might want to take a look at the alert() function, which takes a number of seconds as an argument, such as alert(5). If five seconds was exceeded, an ALERT signal would be generated, which you would catch, and then you could kill the pid based on this.