I pestered dngor on IRC about this unintelligibly for a while before hacking out a solution, but I wanted to post my issue anyway in case it is of some significance. I've posted the code below for reference.
Basically, I was reading from one regular unix file and writing to another regular unix file. The file being read from varies in size, but is always nonzero and generally <= 20MB. My SysRW block size is the default of 512 bytes. Now, if I read a file that is <= 512 bytes, ErrorEvent is immediately triggered and if I check the value of get_driver_out_octets() it will match whatever the file size is and it would never get written to my output handle (when I killed the wheel in the ErrorEvent). With files > 512 bytes seemingly randomly get_driver_out_octets() would tell me that data still needed to be flushed when ErrorEvent was called and I killed my wheel, thus the last few bytes were not being written *ever* if the file was <= 512 bytes and ocassionally when it was > 512 bytes. I hacked a 'solution' below which flags EOF and I have my Flushed event check for it each time the buffer gets flushed, killing the wheel only when there is actually no data left to be read. I no longer lose data, ever, but I don't know if this is a 'POEish' way of dealing with this or not. (This is what I originally thought was being caused by POE Wheel Run, but you see I later tracked it down to this specifically.) --- my $write = new IO::File 'writefile', O_CREAT | O_WRONLY | O_NONBLOCK; my $read = new IO::File 'readfile', O_RDONLY | O_NONBLOCK; $self->copy_file($write, $read); sub copy_file { my( $self, $write_fh, $read_fh ) = @_[0..2]; if(defined $write_fh && defined $read_fh ) { $self->{move} = POE::Wheel::ReadWrite->new( InputHandle => $read_fh, OutputHandle => $write_fh, Driver => POE::Driver::SysRW->new(), Filter => POE::Filter::Stream->new(), InputEvent => 'fh_read', FlushedEvent => 'flush', ErrorEvent => 'fh_error' ); } sub fh_read { my( $self, $record, $wheel_id ) = @_[ OBJECT, ARG0, ARG1 ]; $self->{move}->put( $record ); } sub fh_error { my( $self, $op, $errnum, $errstr, $wheel_id ) = @_[ OBJECT, ARG0, ARG1, ARG2, ARG3 ]; my $pending_octets = $self->{move}->get_driver_out_octets(); my $pending_messages = $self->{move}->get_driver_out_messages(); warn both those, $errnum, and $errstr; # The flush event can finally delete the wheel $self->{EOF} = 'true'; } sub flush { my( $self, $wheel_id ) = @_[ OBJECT, ARG0 ]; if( $self->{EOF} eq 'true' and defined $self->{move} ) { delete $self->{move}; } # The data was flushed -- nothing special needs to happen }