views:

43

answers:

1

I have a program which is calling another program and processing the child's output, ie:

my $pid = open($handle, "$commandPath $options |");

Now I've tried a couple different ways to read from the handle without blocking with little or no success.

I found related questions:

But they suffer from the problems:

  • ioctl consistently crashes perl
  • sysread blocks on 0 bytes (a common occurrence)

I'm not sure how to go about solving this problem.

+3  A: 

Pipes are not as functional on Windows as they are on Unix-y systems. You can't use the 4-argument select on them and the default capacity is miniscule.

You are better off trying a socket or file based workaround.

$pid = fork();
if (defined($pid) && $pid == 0) {
    exit system("$commandPath $options > $someTemporaryFile");
}
open($handle, "<$someTemporaryFile");

Now you have a couple more cans of worms to deal with -- running waitpid periodically to check when the background process has stopped creating output, calling seek $handle,0,1 to clear the eof condition after you read from $handle, cleaning up the temporary file, but it works.

I have written the Forks::Super module to deal with issues like this (and many others). For this problem you would use it like

use Forks::Super;
my $pid = fork { cmd => "$commandPath $options", child_fh => "out" };
my $job = Forks::Super::Job::get($pid);
while (!$job->is_complete) {
    @someInputToProcess = $job->read_stdout();
    ... process input ...
    ... optional sleep here so you don't consume CPU waiting for input ...
}
waitpid $pid, 0;
@theLastInputToProcess = $job->read_stdout();
mobrule
@mobrule my understanding is I can't use select on a filehandle, so this just recreates the same problem I currently have.
tzenes
You don't need to use select on a filehandle. Reading on an exhausted filehandle will return `undef` without blocking, and then you can call `seek HANDLE,0,1` to clear the eof condition and read from it again.
mobrule
@mob would I then have to seek to how far I had already read? Or does that handle it?
tzenes
@tzenes, no, if the 3rd argument to `seek` is `1`, it means seek "relative to the current position". If the 2nd argument is zero, it doesn't have any effect on the cursor position, it just has the desirable side-effect of clearing the eof and error conditions on the handle.
mobrule
@tzense - see the `perldoc -f seek`, especially the example of how to emulate "`tail -f`"
mobrule
@mob I tried the `Forks::Super` code and I got the following error: `Can't locate object method read_stdout via package "Forks::Super::Job"`
tzenes
@tzenes - Forks::Super is a moving target. Make sure you have at least version 0.35.
mobrule