I need to timeout on a script that's doing blocking io.
Surprisingly it turns out exit
hangs if there is an open pipe to a subprocess:
#!/usr/bin/perl
(-f "foo") || die "file foo doesn't exist";
open(IN, "tail -f foo |");
$SIG{ALRM} = sub
{
print "trying to exit...\n";
exit 0; # Hangs with above open() call
};
alarm 1;
while (1)
{
sleep 5; # Do stuff ...
}
With no open
call it works, unfortunately removing it is not an option in this case the script needs it.
Looks like exit
is trying to close the filehandle and this is what is hanging:
$SIG{ALRM} = sub
{
print "trying to close...\n";
close(IN); # Hangs ...
print "ok\n";
exit 0;
};
I guess it's not too happy about reaping the child from inside a signal handler...
Does anyone know a good way around this ?
The signal handler is a red herring, close will block regardless:
open my $foo, "tail -f foo |" or die "Can't open process: $!";
close $foo; # <--- will block
One way to fix this is to capture the sub process id via open and then kill that child:
my $subprocess = open my $foo, "tail -f foo |" or die "Can't open process: $!";
say "subprocess=$subprocess";
kill 'KILL', $subprocess;
close $foo; # <--- happy now
Using POSIX::_exit()
directly like the man page suggests seems to work around this particular issue. But this smells of an A-B problem. Are you sure that your real problem is not better solved by using a more sophisticated way of handling subprocesses than plain pipes, like for example IPC::Run
?
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