Perl can_read returns a handle when there is nothing to read

In the code below, I am trying to perform a simple file operation. Suppose foo.txt is completely empty. I would expect the first can_read () to block, but that is not the case. You also cannot use can_read calls in sysreadline () or wait. Instead, the first can_read immediately returns a handle to foo.txt, and the first can_read in sysreadline does the same. Sysread then returns nothing, because there is nothing to read, which leads to lively waiting inside sysreadline. How can it be? I know that the choice may end earlier due to a signal or a closed file descriptor, but I do not see any possibility for this here. In fact, when the text appears (with a new line) in the foo.txt file, it prints. I don’t understand why the code does not block indefinitely, like the first can_read, when there is nothing to read.In addition to wasting CPU, this makes it impossible to use multiple files at the same time, because you will always get stuck in the first wait. I feel like I should overlook something simple ...

This is perl 5.8.8



#!/usr/bin/perl -w
use strict;
use IO::Select;
use IO::Handle; 
use Symbol qw(qualify_to_ref); 

open my $inf, "<", "foo.txt" or die "hey! Can't open foo.txt!\n";
my $sel = IO::Select->new();
$sel->add($inf);

while(my @ready = $sel->can_read()){

    foreach my $handle (@ready){
    my $line = sysreadline($handle);
    print $line;
    }

}

##
## deal with buffering for select. from perl cookbook 7.23
sub sysreadline {
    my($handle, $timeout) = @_;
    $handle = qualify_to_ref($handle, caller( ));
    my $infinitely_patient = (@_ == 1 || $timeout new( );
    $selector->add($handle);
    my $line = "";
SLEEP:
    until (at_eol($line)) {
        unless ($infinitely_patient) {
            return $line if time( ) > ($start_time + $timeout);
        }
        # sleep only 1 second before checking again
        next SLEEP unless $selector->can_read(1.0);
INPUT_READY:
        while ($selector->can_read(0.0)) {
            my $was_blocking = $handle->blocking(0);
CHAR:       while (sysread($handle, my $nextbyte, 1)) {
                $line .= $nextbyte;
        ##print "next: [$nextbyte]\n";
                last CHAR if $nextbyte eq "\n";
            }
            $handle->blocking($was_blocking);
            # if incomplete line, keep trying
            next SLEEP unless at_eol($line);
            last INPUT_READY;
        }
    }
    return $line;
}
sub at_eol($) { $_[0] =~ /\n\z/ }

+5
source share
1 answer

Returning from selectmeans that "reading will not be blocked (that is, wait forever for any external event)" and not "data is available." Reading files from disk never blocks; it immediately returns 0 to EOF.

This way you will probably be better off with the File :: Tail that @TLP offers.

+7
source

All Articles