Re: SIG{ALRM} to help kill external program
by cdarke (Prior) on Oct 13, 2010 at 14:12 UTC
|
Alarm handlers do not survive a fork (which hides under the covers of backticks), this is not Perl specific, it is a feature of UNIX. So you need to use fork, do the signal handling in the child, then exec your external application. See also Proc::Background which includes timeout handling (it uses sleep for the timeout). | [reply] |
|
cdarke:
Can you point to some documentation? I did a quick search (not very thorough), and haven't found any evidence that the alarm handlers don't survive a fork. The OpenGroup alarm documentation clearly states that pending alarm signals are cleared for the child, and their fork docs state that the child process will have its alarm cleared and any pending alarm reset. So I don't see why the parent using alarm & kill wouldn't work.
I don't have my hands on a Unix box at the moment, but under windows, I get this:
301058@LOU-PC0288 /Work/METABASE
$ perl forktest.pl
nofork: ALARM!
nofork: done...
301058@LOU-PC0288 /Work/METABASE
$ perl forktest.pl a
PID(2560): ALARM!
PID(0): QUITTING!
PID(2560): done...
301058@LOU-PC0288 /Work/METABASE
$ cat forktest.pl
use strict;
use warnings;
my $prefix="nofork";
my $PID;
$SIG{INT} = sub { die "$prefix: QUITTING!\n\n"; };
$SIG{ALRM} = sub { print "$prefix: ALARM!\n\n"; kill 2,$PID if $PID; }
+;
alarm(5);
if (@ARGV) {
# with any argument we fork, o/w we don't
$PID = fork;
$prefix = "PID($PID)";
}
# Wait long enough for alarm to trigger
my $t = time;
while ($t + 10 > time) {
# doze
}
print "$prefix: done...\n\n";
alarm(0);
301058@LOU-PC0288 /Work/METABASE
$
...roboticus
| [reply] [d/l] |
Re: SIG{ALRM} to help kill external program
by roboticus (Chancellor) on Oct 13, 2010 at 13:46 UTC
|
locked0wn:
I'd suggest forking off the job and retaining the process ID. Then you can use your signal for the timeout, and kill the child process if it's still executing:
my $SIGINT=2;
my $PID=fork("my command");
. . .
sub SIGHANDLER {
kill $SIGINT, $PID;
}
...roboticus
| [reply] [d/l] |
Re: SIG{ALRM} to help kill external program
by BrowserUk (Patriarch) on Oct 13, 2010 at 14:34 UTC
|
| [reply] |
Re: SIG{ALRM} to help kill external program
by kennethk (Abbot) on Oct 13, 2010 at 14:06 UTC
|
The behaviors of backticks are described in `STRING` in perlop. Backticks only return once the external program has finished execution - otherwise, how would perl know it had returned to you the entire output? Therefore, you can't use a $SIG{ALRM} to control it - the child process has control of the thread. For the simple case, you can follow roboticus's suggestion to use fork.(Update: See cdarke's comment below) You might also consider threads (core) or POE for more complicated queuing behaviors. If you are feeling adventurous, you can combine a piped open with select or $SIG{ALRM} - see Using open() for IPC some some basics.
| [reply] |
|
kennethk,
I want to thank you for your suggestion of using threads. I have implemented a dual thread setup that uses a shared variable for tracking completion of thread 1, which launches the external application. Thread 2 monitors the value of the shared variable, and after several loops of checking state on the variable, it either ends the thread (which means that thread 1 completes), or it kills all threads, because thread 1 has been hung up (which means the external app did not complete. It works very well, and I intend to post after I clean up the code for final. Thank you very much for everyones' input.
| [reply] |
Re: SIG{ALRM} to help kill external program
by locked_user sundialsvc4 (Abbot) on Oct 13, 2010 at 17:42 UTC
|
If it were me, I’d follow the suggestion of forking-off the analysis program as a child of a command-process that then goes to sleep waiting for it to end, or to receive a signal. This controller-program can do nice things like set priorities for the child, divert its output this way or that, set up any peculiar things that the child might need, and even monitor it to see if it is still consuming CPU time. Upon receipt of the proper signal, the controller program deals the coup de grace to the analysis program, waits to bury it and set up a nice tombstone, and so on. None of this magick is visible to anyone who just wants “to analyze a file,” but it really works out well.
| |
Re: SIG{ALRM} to help kill external program
by jakeease (Friar) on Oct 13, 2010 at 23:55 UTC
|
A couple suggestions from the Perl Cookbook -- not sure if they are what you need but here they are.
16.19 Avoiding Zombie Processes
If you don’t need to record the children that have terminated, use:
$SIG{CHLD} = 'IGNORE';
If you do, use a SIGCHLD handler:
$SIG{CHLD} = \&REAPER;
sub REAPER {
my $stiff;
while (($stiff = waitpid(-1, WNOHANG)) > 0) {
# do something with $stiff if you want
}
$SIG{CHLD} = \&REAPER; # install *after* calling waitpid
}
some info on waitpid & WNOHANG:
http://www.mkssoftware.com/docs/man3/waitpid.3.asp | [reply] [d/l] [select] |