I browsed around and read a few other questions about getting a command to stop running after a period of time but everything i tried doesn't work.
The command will act like it wants to stop after the specified amount of time (It returns the terminal prompt for a brief second) but just keeps going and wont stop.
Here is my code:
#!/usr/bin/perl
use strict;
use warnings;
use Try::Tiny;
try {
local $SIG{ALRM} = sub { die "alarm\n" };
alarm 5;
system("ping 192.168.1.1");
alarm 0;
}
catch {
die $_ unless $_ eq "alarm\n";
print "timed out\n";
};
exit;
The output in the terminal looks like this:
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=1.98 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=3.13 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=3.20 ms
64 bytes from 192.168.1.1: icmp_seq=4 ttl=64 time=3.17 ms
64 bytes from 192.168.1.1: icmp_seq=5 ttl=64 time=3.16 ms
64 bytes from 192.168.1.1: icmp_seq=6 ttl=64 time=3.11 ms
64 bytes from 192.168.1.1: icmp_seq=7 ttl=64 time=3.18 ms
64 bytes from 192.168.1.1: icmp_seq=8 ttl=64 time=3.20 ms
64 bytes from 192.168.1.1: icmp_seq=9 ttl=64 time=3.22 ms
64 bytes from 192.168.1.1: icmp_seq=10 ttl=64 time=3.20 ms
skilo@hp-xubuntu:~/perlstuff$ 64 bytes from 192.168.1.1: icmp_seq=11 ttl=64 time=3.06 ms
64 bytes from 192.168.1.1: icmp_seq=12 ttl=64 time=3.19 ms
64 bytes from 192.168.1.1: icmp_seq=13 ttl=64 time=3.21 ms
64 bytes from 192.168.1.1: icmp_seq=14 ttl=64 time=3.21 ms
Notice how it tries to stop but can't.
The perl 'system' builtin function forks your process, and in the child process created by the fork, it executes the 'ping' program. Then, the parent process waits on the child process to finish.
Your alarm timer and signal handler interrupts the waiting process, and then terminates the parent, leaving the child process running in the background.
What you will need to do is:
Try this:
#!/usr/bin/perl
use strict;
use warnings;
eval {
local $SIG{ALRM} = sub { die "alarm\n" };
alarm 5;
system("ping -v 192.168.1.1");
alarm 0;
};
if ($@) {
die $@ unless $@ eq "alarm\n";
print "timed out\n";
kill 2, -$$;
wait;
};
exit;
Note: I did not have Try::Tiny on my system so I replaced that with old-school eval blocks. But it should work the same.
This 'kill' command takes a signal number (I used 2 for SIGINT, which is equivalent to pressing ctrl-c) and one or more processes to kill. $$ is the pid of the current process; a negative value has the effect of killing the whole process group associated with the current process (which effectively means all child processes). Note that this is not completely portable - if you find that it does not work on your system then you are going to need to be able to find the actual PID of the child process. To be able to do that you should replace system with calls to fork and then exec, like this:
#!/usr/bin/perl
use strict;
use warnings;
my $childPid;
eval {
local $SIG{ALRM} = sub { die "alarm\n" };
alarm 5;
if ($childPid = fork()) {
wait();
} else {
exec("ping -v 192.168.1.1");
}
alarm 0;
};
if ($@) {
die $@ unless $@ eq "alarm\n";
print "timed out\n";
kill 2, $childPid;
wait;
};
exit;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With