Perl subprocess signaling

I have a perl script that runs a series of batch scripts to test regression. I want to implement a timeout for batch scripts. I currently have the following code.

my $pid = open CMD, "$cmd 2>&1 |"; eval { # setup the alarm local $SIG{ALRM} = sub { die "alarm\n" }; # alarm on the timeout alarm $MAX_TIMEOUT; log_output("setting alarm to $MAX_TIMEOUT\n"); # run our exe while( <CMD> ) { $$out_ref .= $_; } $timeRemaining = alarm 0; }; if ( $@ ) { #catch the alarm, kill the executable } 

The problem is that no matter what I set the maximum latency for, the alarm never works. I tried using Perl :: Unsafe :: Signals, but that didn't help.

Is this the best way to execute batch scripts if I want them to be able to write their output? Is there another way that will do the same that will allow me to use alarms, or is there any other method besides alarms for the program timeout?

I built a test script to confirm that the alarm works with my version of perl and windows, but it does not work when I run such a command.

I run this with activeperl 5.10.1 on Windows 7 x64.

+6
source share
1 answer

It is difficult to say when alarm will work, when a system call will and will not be interrupted by SIGALRM , how the same code can behave differently in different operating systems, etc.

If your work is over, you want to kill the initial subprocess. This is a good precedent for a poor person's anxiety:

 my $pid = open CMD, "$cmd 2>&1 |"; my $time = $MAX_TIMEOUT; my $poor_mans_alarm = "sleep 1,kill(0,$pid)||exit for 1..$time;kill -9,$pid"; if (fork() == 0) { exec($^X, "-e", $poor_mans_alarm); die "Poor man alarm failed to start"; # shouldn't get here } # on Windows, instead of fork+exec, you can say # system 1, qq[$^X -e "$poor_mans_alarm"] ... 

Poor anxiety is triggered in a separate process. Every second, it checks if the process with the id $pid alive. If the process is inactive, the alarm process ends. If the process is still alive after $time seconds, it sends an error signal to the process (I used 9 to make it uncaught and -9 take out the whole subprocess tree, your needs may vary).

( exec may actually not be necessary. I use it because I also use this idiom to monitor processes that can survive the Perl script that launched them. Since this is not the case with this problem, you can skip the exec call and to tell

 if (fork() == 0) { for (1..$time) { sleep 1; kill(0,$pid) || exit } kill -9, $pid; exit; } 

instead of this.)

+4
source

Source: https://habr.com/ru/post/903486/


All Articles