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

I want to spawn an external process and if it does not return in a certain amount of time return control to the perl code and use some defaults instead of the data from the external process. The external process has no concept of timeouts so they have to be done in the perl code. How do I interrupt processes like this in my perl code?
# psuedo - code

my($cmd) = "/run/external/prog";
my(@results) = `$cmd`; 

@results = defaults unless ($cmd finished in x secs);

Replies are listed 'Best First'.
Re: how to make timeouts?
by cephas (Pilgrim) on Dec 02, 2000 at 02:26 UTC
    I'd recommend using an alarm and eval combination to get the desired effect. Here's a sample:

    local $SIG{ALRM} = sub { die("TIMED OUT") }; eval { alarm(10); #set our alarm for 10 seconds @results = `$cmd`; alarm(0); } if($@ =~ /TIMED OUT/) { #do defaults }


    This should allow you to do the time out without having to do a fork. When the die occurs, you will break out of the eval, and $@ will be set with the error message that you died with from your SIGALRM handler. I believe I picked this trick up out of ORA's Advanced Perl Programming, but I'm not %100 positive.

    Update: I double checked in the Advanced Perl Programming book, and there is indeed an example almost identical to what I posted on pages 80-81 (I won't repost their version, because the two are more or less equivalent, they actually used a reference to a named sub in the sighandler vs my anonymous sub.) Just wanted to make sure I gave credit to where I originally had learned this.

    cephas
      The message I'm replying to was posted a looong time ago, but for visitors like me: you've forgot the tiny semicolon right after the eval block.
Re: how to make timeouts?
by Blue (Hermit) on Dec 02, 2000 at 02:08 UTC
    Two suggestions.

    You could fork off the other program, and kill it and use a default if it does not return in your specified timeout period.

    Or use alarm to set a timeout & $SIG{ALRM} to set up defaults in the case that your external command did not return. That assumes that your external command is not blocking execution of your Perl, so you may have to fork it off anyway.

    =Blue
    ...you might be eaten by a grue...

Re: how to make timeouts?
by rpc (Monk) on Dec 02, 2000 at 02:05 UTC
    You can do this using the alarm function, and using a signal handler.
    perldoc -f alarm