Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl: closing subprocess pipe in signal handler hangs?

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 ?

like image 326
lemonsqueeze Avatar asked Jan 25 '16 05:01

lemonsqueeze


2 Answers

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
like image 93
Miller Avatar answered Oct 15 '22 18:10

Miller


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?

like image 35
Calle Dybedahl Avatar answered Oct 15 '22 17:10

Calle Dybedahl