I am attempting to deal with the following scenario, and so far my attempts have been unsuccessful.
I want to run a variety of commands, they all should not require user input, but there is a chance one might. Because of this I want to implement a timeout for these calls, so that we don't wait indefinitely.
The most logical way to do this that I see is to fork a process, have that process run the command and monitor the process, if it hasn't returned in X amount of time kill the $pid. But I am running up against a few issues with this, the largest of which is dealing with the sub-process. I am using backticks to actually run the command because I need the output, when I go about killing the forked process, it does not kill the "backticked" sub-proces.
I noticed someone else posted something somewhat similar to what I am seeing, but the solution for that did not work for me.
I have tried the following so far to no avail:
Option 1:
sub _timedFork1 { my ($command, $time) = @_; my @resp1; my $pid; my @pids; local $SIG{ALRM} = sub {kill -15, $pid or die "kill: $!"; die "TIMEOUT!"; }; if ($pid = fork()) { push(@pids, $pid); alarm $time; waitpid($pid, 0); } elsif (defined $pid) { @resp1 = `$command`; return @resp1; exit; } return ($pid, @resp1) }
OPTION 2:
sub _timedFork2 { my ($command, $time) = @_; my $pid; my @resp2; local $SIG{ALRM} = sub {kill 15, $pid or die "kill: $!"; die 'Timeout!'; }; eval { $pid = fork(); unless (defined $pid) { die "Fork failed: $!"; } unless ($pid) { @resp2 = `$command`; } alarm $time; waitpid $pid => 0; }; if ($@ and $@ !~ m/Timeout!/i) { die $@; } return @resp2; }
OPTION 3:
sub _forkFHCommand { my ($command, $time) = @_; my @resp3; my $pid = open COMMAND, "-|", $command or die $!; my $endtime = time() + $time; my $line; while($line = <COMMAND>) { push(@resp3, $line); if (time > $endtime) { kill 15, $pid; last; } } close COMMAND; return (0, @resp3); }
As a note in the $SIG{ALRM}, I tried kill 9, kill -9 and kill 15. None of them worked for me.
I also attempted to do a simple fork function and have the main script sleep for a set amount of time, and then attempt to kill the $pid, this also didn't work out for me.
Essentially the perfect solution would enable me to get back whatever has been returned from the command prior to it being killed. Also, it obviously needs to be able to kill the sub-process.
I am completely open to using threads, but so far my attempts at that have resulted in hangs
So just to summarize the main issue I am having is with processes waiting for input. The _forkFHCommand solution works fine for commands that take a long time but don't require user input (i.e. do a ping -n 100 192.168.1.2 with a timeout of 5 seconds). The other solutions show the same issue of a leftover sub-process regardless if it that sub-process is waiting for input or not.
Any help would be greatly appreciated. Thanks.
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |