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

Hello monks, I have a current working perl script on Unix that calls another perl script using system(...); . However, it would be useful to me to leave the call running in the background and continue with the rest of the code from the original script after , say , ten seconds or so. If this is the case, I also need some way of knowing that this happened and send a message to another app. Any ideas or advice are greatly appreciated. Thank you.
  • Comment on Ending system() calls after certain time period.

Replies are listed 'Best First'.
Re: Ending system() calls after certain time period.
by Fletch (Bishop) on Jun 23, 2008 at 14:51 UTC

    Apparently today is "See how many times you can recommend IPC::Run" day. (There's also alarm and more info in perlipc . . .)

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: Ending system() calls after certain time period.
by moritz (Cardinal) on Jun 23, 2008 at 14:53 UTC
    You can fork, set a time limit in the child with BSD::Resource, and exec the external program.

    That does the time limit part, but I don't know how to notify other programs of a timeout - perhaps trapping some signals might help.

    You can also look on cpan for ipc, run and system, maybe one of the great many modules does that job for you already.

      You can try using something like a named pipe.

      Edit: when I've seen named pipes used as a timing mechanism, it was when there was a process that could run to completion in X seconds or then be killed. You would set up two coprocesses in a shell, one monitoring the other. When time was up, one process would kill the other if it had not completed and sent the completion message through the pipe. I'm not sure if the questioner is wanting a run or die scenario.
      BSD::Resource RLIMIT_CPU apparently does not work in linux:
      h@e12a8t:~$ perl -le 'use BSD::Resource; print for RLIMIT_CPU, q(--), +getrlimit(RLIMIT_CPU), q(--), getrusage(), q(--), setrlimit(RLIMIT_CP +U, 10, 20), qq(--), getrlimit(RLIMIT_CPU), q(--); $SIG{XCPU} = sub { +print "LIMIT" }; (sleep 1), printf "$_: %s %s\n", getrusage() for 1 . +. 100;' 0 -- -1 -1 -- 0.024001 0.008 0 0 0 0 685 0 0 0 0 0 0 0 1 0 -- 1 -- 10 20 -- 1: 0.024001 0.008 2: 0.024001 0.008 3: 0.024001 0.008 4: 0.024001 0.008 5: 0.024001 0.008 6: 0.024001 0.008 7: 0.024001 0.008 8: 0.024001 0.008 9: 0.024001 0.008 10: 0.024001 0.008 11: 0.024001 0.008
      goes all the way up to 100.
        A well, I guess it just limits CPU time and not run time - perhaps not what the OP wanted. Your script doesn't really use much CPU time (less than 0.03 on my machine), so it won't get killed.

        That's fine for my applications, but perhaps not so good in the general application.

Re: Ending system() calls after certain time period.
by pjotrik (Friar) on Jun 23, 2008 at 14:59 UTC
    A sample from perlipc:
    eval { local $SIG{ALRM} = sub { die "alarm clock restart" }; alarm 10; flock(FH, 2); # blocking write lock alarm 0; }; if ($@ and $@ !~ /alarm clock restart/) { die }
Re: Ending system() calls after certain time period.
by zentara (Cardinal) on Jun 23, 2008 at 16:58 UTC
    Here's a neat one by edan, that ought to work for you.
    #!/usr/bin/perl use strict; use warnings; # by edan of perlmonks, works great spawn(5, "xterm"); spawn(5, "xterm"); spawn(5, "xterm"); spawn(5, "xterm"); print "Hit enter to quit\n"; <>; sub spawn { my ($timeout, @cmd) = @_; defined( my $child_pid = fork ) or die "fork: $!"; if ($child_pid) { # parent eval { local $SIG{ALRM} = sub { timeout($child_pid); }; alarm $timeout; waitpid $child_pid, 0; alarm 0; }; if ($@){print "oops: $@";} }else{ # child exec @cmd or die "exec: $!"; } } sub timeout { my ($pid) = @_; kill 'TERM' => $pid; waitpid $pid, 0; die "reaped $pid\n"; }

    I'm not really a human, but I play one on earth CandyGram for Mongo
Re: Ending system() calls after certain time period.
by psini (Deacon) on Jun 23, 2008 at 14:54 UTC

    Fork. The child execute the system call, the parent sleeps the desired time and then send the message.

    If the child terminates before the timeout, wakes the parent and the message is not sent.

    Could it work?

    Careful with that hash Eugene.