The problem is that select() isn't re-entrant: it gets interrupted by the signal handler and doesn't resume, so you end up with an empty @ready array. That means you fall out of the while (@ready) {} loop; the sub returns, createProcess() is called again, the file handles are re-opened: the previous command is terminated.
To work around that, add a flag variable which gets reset in the handler:
my $redo; # flag
sub status () {
$SIG{USR1} = \&status;
print STDERR "Currently running: $StartedProcess\n";
$redo = 1; # re-set flag
}
# Opens external program, and as long as it exists, checks
# if there is data in the pipe (STDOUT/STDERR)
sub createProcess () {
my($line, $selector, @ready, $fh);
$StartedProcess = open3(*CMD_IN, *CMD_OUT, *CMD_ERR, "./external.pp"
+);
close(CMD_IN);
$selector = IO::Select->new();
$selector->add(*CMD_ERR, *CMD_OUT);
$redo = 1; # set flag
while($redo) {
$redo = 0; # clear flag
while(@ready = $selector->can_read) {
# do some operations on STDOUT/STDERR here
}
warn "after inner loop\n";
}
warn "closing CMD_OUT and CMD_ERR\n";
close(CMD_OUT);
close(CMD_ERR);
}
Also, you should set up a SIGCHLD handler which clears the $selector after the child is gone.
|