Assuming a handle created with the following code:
use IO::File;
my $fh = IO::File->new;
my $pid = $fh->open('some_long_running_proc |') or die $!;
$fh->autoflush(1);
$fh->blocking(0);
and then read with a loop like this:
while (some_condition_here) {
my @lines = $fh->getlines;
...
sleep 1;
}
What do I put as some_condition_here
that will return false if the process on the other end of the pipe has terminated?
Testing for $fh->eof
will not work since the process could still be running without printing any new lines. Testing for $fh->opened
doesn't seem to do anything useful.
Currently I am using $pid =! waitpid($pid, WNOHANG)
which seems to work in POSIX compliant environments. Is this the best way? What about on Windows?
On using select
,
use strict;
use warnings;
use IO::Select qw( );
sub process_msg {
my ($client, $msg) = @_;
chomp $msg;
print "$client->{id} said '$msg'\n";
return 1; # Return false to close the handle.
}
my $select = IO::Select->new();
my %clients;
for (...) {
my $fh = ...;
$clients{fileno($fh)} = {
id => '...'
buf => '',
# ...
};
$select->add($fh);
}
while (my @ready = $select->can_read) {
for my $fh (@ready) {
my $client = $clients{ fileno($fh) };
our $buf; local *buf = \( $client->{buf} );
my $rv = sysread($fh, $buf, 64*1024, length($buf));
if (!$rv) {
if (defined($rv)) {
print "[$client->{id} ended]\n";
} else {
print "[Error reading from $client->{id}: $!]\n";
}
print "[Incomplete message received from $client->{id}]\n"
if length($buf);
delete $clients{ fileno($fh) };
$select->remove($fh);
next;
}
while ($buf =~ s/^(.*\n)//) {
if (!process_msg($client, "$1")) {
print "[Dropping $client->{id}]\n";
delete $clients{ fileno($fh) };
$select->remove($fh);
last;
}
}
}
}
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