开发者

perl can_read returns handle when there is nothing to read

In the below code, I am attempting to perform a simple file tail operation. Assume foo.txt is completely empty. I would expect that the first can_read() would block but it does not. Nor do the can_read calls in sysreadline() block or wait either. Instead what happens is that the first can_read immediately returns the handle to foo.txt an开发者_StackOverflowd the first can_read in sysreadline does the same. The sysread then returns nothing because there is nothing to read, which results in a busy wait inside sysreadline. How can this be? I know a select can end early due to a signal or closed file handle, but I don't see any opportunity for that here. In fact, when text does appear (with a newline) in foo.txt, it is printed. I don't see why the code doesn't block indefinitely as the first can_read when there is nothing to read. In addition to wasting cpu, it makes it impossible to tail multiple files at the same time because you will always get stuck in the first busy wait. I feel like I must be overlooking something simple here...

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/ }


The return from select means "read will not block (i.e. wait forever for some external event to happen)", and not "data is available". Reading files from disk never blocks, it returns 0 immediately at EOF.

So you're probably better off with File::Tail that @TLP suggests.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜