Skip to content

Instantly share code, notes, and snippets.

@groner
Created September 8, 2017 20:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save groner/7d887c400749a4c82303773bf2dddcb5 to your computer and use it in GitHub Desktop.
Save groner/7d887c400749a4c82303773bf2dddcb5 to your computer and use it in GitHub Desktop.
wrapper script to run a command with a timeout
use POSIX qw(WNOHANG WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG);
use Time::HiRes qw(gettimeofday);
die "usage: $0 TIMEOUT COMMAND ...\n" if (@ARGV < 2);
$timeout = shift @ARGV;
$pid = fork();
die "fork: $!" if not defined $pid;
if ($pid == 0) {
exec @ARGV or die "$ARGV[0]: $!";
}
$SIG{"CHLD"} = sub {
waitpid $pid, WNOHANG;
exit WEXITSTATUS($?) if WIFEXITED($?);
if (WIFSIGNALED($?)) {
kill WTERMSIG($?), $$;
# Still here? Signal was handled, so just report it and exit.
die "Signal ${WTERMSIG($?)}";
}
};
$endtime = gettimeofday()+$timeout;
sleep($endtime-gettimeofday()) while (gettimeofday() < $endtime);
print STDERR "timeout!\n";
kill "TERM", $pid;
while (1) { sleep(1) }
@groner
Copy link
Author

groner commented Sep 8, 2017

Could use a second timeout with a hard kill.
Doesn't try to relay signals. It could run in the background, and poll. Polling is ugly, and it could mistarget the wrong process when pids are recycled.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment