Well, here's the actual module $buffer uses:
package IRC::Buffer; use strict; use warnings; use IO::Select; use Carp; ################# # Class Methods # ################# sub new { my $self = bless({}, shift); $self->{'IO'} = IO::Select->new; @{$self->{'FH'}} = (); $self->{'Filehandles'} = {}; return $self; } ################## # Object Methods # ################## sub add { my($self, $fh) = @_; unless(fileno($fh) =~ /^\d+$/) { croak "$fh is not a valid filehandle"; return; } $self->{'IO'}->add($fh); push(@{$self->{'FH'}}, $fh); @{$self->{'Filehandles'}{$fh}{'Queue'}} = (); #an array tha +t will hold complete lines $self->{'Filehandles'}{$fh}{'Fract'} = ''; #a scalar to +store a fragment of a line $self->{'Filehandles'}{$fh}{'Pattern'} = '\r\n|\r|\n'; #default line +end pattern $self->{'Filehandles'}{$fh}{'Size'} = 4096; #amount of by +tes read per sysread() return 1; } sub remove { my($self, $fh) = @_; unless(fileno($fh) =~ /^\d+$/) { croak "$fh is not a valid filehandle"; return; } $self->{'IO'}->remove($fh); my $c = 0; foreach(@{$self->{'FH'}}) { if($_ eq $fh) { splice(@{$self->{'FH'}}, $c, 1); last; } else { $c++; } } delete $self->{'Filehandles'}{$fh}; return 1; } sub set_pattern { my($self, $fh, $pattern) = @_; $self->{'Filehandles'}{$fh}{'Pattern'} = $pattern; } sub set_size { my($self, $fh, $size) = @_; unless($size =~ /^\d$/) { croak "argument to \'set_size\' must be integer"; return; } $self->{'Filehandles'}{$fh}{'Size'} = $size; return 1; } sub ready { my $self = shift; my @ready = $self->{'IO'}->can_read(0.001); my $already_listed; foreach my $fh (@{$self->{'FH'}}) { if(@{$self->{'Filehandles'}{$fh}{'Queue'}}) { foreach(@ready) { if($_ eq $fh) { $already_listed = 1; last; } } } unless($already_listed) { push(@ready, $fh); } } return @ready; } sub sysreadline { my($self, $fh) = @_; my $read; unless($self->{'Filehandles'}{$fh}) { return; } unless(@{$self->{'Filehandles'}{$fh}{'Queue'}}) { unless($read = $self->_fill_buffer($fh)) { return $read; } while($read == $self->{'Filehandles'}{$fh}{'Size'}) { $read = $self->_fill_buffer($fh); } } return shift(@{$self->{'Filehandles'}{$fh}{'Queue'}}) . "\n"; } #################### # Internal methods # #################### sub _fill_buffer { #reads x bytes in from the specified filehandle, chops them up into +lines and returns # the number of bytes read when succesful, 0 when eof or undef when +an error occurs. my($self, $fh) = @_; my $pattern = $self->{'Filehandles'}{$fh}{'Pattern'}; my($chunk, $read); #attempt to perform a sysread on the filehandle and process the data +. # if the read fails it will return 0 for end of file or undef for a +read error # while setting $! to the reason for the error unless($read = sysread($fh, $chunk, $self->{'Filehandles'}{$fh}{'Siz +e'})) { return $read; } #there is a possibility that what we have just read is simply the mi +ddle section of a # single line, so check for that first: unless($chunk =~ /$pattern/) { $self->{'Filehandles'}{$fh}{'Fract'} .= $chunk; return 0; } #if the first character of $chunk is a newline, then what we current +ly have listed as a broken line # from the last read is in fact a regular full line, so we can go ah +ead and add it to the queue. if(($chunk =~ /^[$pattern]/) && ($self->{'Filehandles'}{$fh}{'Fract' +})) { push(@{$self->{'Filehandles'}{$fh}{'Queue'}}, $self->{'Filehandles +'}{$fh}{'Fract'}); $self->{'Filehandles'}{$fh}{'Fract'} = ''; } my @lines = split(/$pattern/, $chunk); #otherwise if we still have a broken line sitting around, merge it w +ith the first line of @lines # and then add it to the queue if($self->{'Filehandles'}{$fh}{'Fract'}) { push(@{$self->{'Filehandles'}{$fh}{'Queue'}}, $self->{'Filehandles +'}{$fh}{'Fract'} . shift(@lines)); $self->{'Filehandles'}{$fh}{'Fract'} = ''; } #if the last character of $chunk is a newline, then there is no actu +al broken line in this batch, # so we can simply process all the lines in order. otherwise make su +re the last line in @lines is # treated as a fragment unless($chunk =~ /[$pattern]$/) { $self->{'Filehandles'}{$fh}{'Fract'} = pop(@lines); } #now simply push all of @lines into the queue push(@{$self->{'Filehandles'}{$fh}{'Queue'}}, @lines); return $read; }
I can't see anything in there that might cause this behavior. All it really does is create an artificial buffer so I could stuff the dirty work of processing unbuffered reads somewhere nicely out of sight.


Remember rule one...

In reply to Re^2: select loop madness by Forsaken
in thread select loop madness by Forsaken

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.