http://qs321.pair.com?node_id=337705

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

I have a utility I need to run with system() that takes a varying amount of time to execute. Maybe a few seconds, maybe 20 minutes. Sometimes it wanders off into oblivion and never returns. When that happens, I need to kill and restart it.

Is there a way to have a timeout with a system() call, so I can do this kill-and-restart through Perl?

---
A fair fight is a sign of poor planning.

Replies are listed 'Best First'.
Re: system() with timeout
by Abigail-II (Bishop) on Mar 18, 2004 at 15:52 UTC
    Don't do it with system directly, or you might generate zombies. fork(), do an exec() in the child, and then, in an eval block, setup an alarm handler that does a die(), set the alarm, waitpid() for your child, cancel the alarm. Outside the eval block, check for $@, if it indicates the alarm was triggered, kill the child and waitpid() for it.

    No doubt there are some race conditions left in, but it's a start.

    Abigail

Re: system() with timeout
by delirium (Chaplain) on Mar 18, 2004 at 15:53 UTC
    Yes. Here's an example of some code I use that does this (but alarm, as I've heard, may be unsafe in older Perls):

    #!/usr/bin/perl use strict; use warnings; my $timeout = 180; my @array = ( "command 1 goes here", "command 2 goes here", "command 3 goes here", ); for (@array) { eval { local $SIG{ALRM} = sub { die "alarm\n"; }; alarm $timeout; system($_); alarm 0; };
Re: system() with timeout
by valdez (Monsignor) on Mar 18, 2004 at 15:59 UTC

    ... and if you are lazy, take a look at IPC::Run :)

    Ciao, Valerio

    update: many thanks to waswas-fng (who was not lazy)

      One thing I have been bitten on before using IPC::Run is pty issues on heavy loaded machines -- it caused a hard to track down error for me. from the pod:
      =item pty Support

      If you need pty support, IPC::Run should work well enough most of the time, but IO::Pty is being improved, and IPC::Run will be improved to use IO::Pty's new features when it is release. The basic problem is that the pty needs to initialize itself before the parent writes to the master pty, or the data written gets lost. So IPC::Run does a sleep(1) in the parent after forking to (hopefully) give the child a chance to run. This is a kludge that works well on non heavily loaded systems :(.


      -Waswas


      Update: I am not saying its a bad module, just that I have hit the pty issue before and it was a PITA to track down. My fix was to change the sleep 1 to sleep 2 in the module, but there is still a race condition there you just make it a little less likely to happen.
Re: system() with timeout
by Tomte (Priest) on Mar 18, 2004 at 15:51 UTC

    Super Search for 'system timeout', and you will find what you seek; if I err on that, refer to have a closer look on perldoc -f alarm

    regards,
    tomte


    Hlade's Law:

    If you have a difficult task, give it to a lazy person --
    they will find an easier way to do it.

Re: system() with timeout
by ambrus (Abbot) on Mar 18, 2004 at 15:59 UTC
      Dang. I'm stuck with 5.6.1, so it looks like the alarm method isn't going to work for me...

      ---
      A fair fight is a sign of poor planning.

        Why not. 5.6.1 supports alarm, just not on Win32.

        cheers

        tachyon

Re: system() with timeout
by eyepopslikeamosquito (Archbishop) on Mar 19, 2004 at 06:19 UTC

    If you are using Win2K and above, I recommend the Win32::Job module. Some example code, using either Win32::Process or Win32::Job, can be found in Timing Windows commands.