Skip Menu |

This queue is for tickets about the IO-Async CPAN distribution.

Report information
The Basics
Id: 101919
Status: resolved
Priority: 0/
Queue: IO-Async

People
Owner: Nobody in particular
Requestors: DBOOK [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: 0.64
Fixed in: 0.65



Subject: Loop::Select - Error when I/O notifiers are removed during callback
Error shows up in this report (because win32 gets forced to Select): http://www.cpantesters.org/cpan/report/411f6e2d-6bfe-1014-9b74-0ee4eeb7ca3d Can't call method "fileno" on an undefined value at <...>/IO/Async/Loop/Select.pm line 182. It happens when two Handle notifiers are added, and the callback for one removes both notifiers from the loop. I've extracted a test case: http://paste.fedoraproject.org/181199/23025377/raw/
Uploaded test case to RT as the fpaste might expire
Subject: undef_watcher_fileno.t
use strict; use warnings; use Test::More; use IO::Async::Loop::Select; use IO::Async::Handle; use IO::Socket::INET; my $listen = IO::Socket::INET->new(Listen => 5, LocalAddr => '127.0.0.1'); my $port = $listen->sockport; my $client = IO::Socket::INET->new(PeerAddr => '127.0.0.1', PeerPort => $port); my $server = $listen->accept; my $loop = IO::Async::Loop::Select->new; my %watchers; $watchers{fileno $client} = add_watcher($loop, $client); $watchers{fileno $server} = add_watcher($loop, $server); $loop->watch_time(after => 1, code => sub { $loop->stop }); $loop->loop_forever; ok(!$loop->notifiers, 'I/O watchers have been removed'); done_testing(); sub add_watcher { my ($loop, $handle) = @_; my $w = IO::Async::Handle->new( write_handle => $handle, on_write_ready => sub { $watchers{$_}->remove_from_parent for keys %watchers }, want_writeready => 1, ); $loop->add($w); return $w; }
On Wed Feb 04 00:01:55 2015, DBOOK wrote: Show quoted text
> Error shows up in this report (because win32 gets forced to Select): > http://www.cpantesters.org/cpan/report/411f6e2d-6bfe-1014-9b74- > 0ee4eeb7ca3d > > Can't call method "fileno" on an undefined value at > <...>/IO/Async/Loop/Select.pm line 182. > > It happens when two Handle notifiers are added, and the callback for > one removes both notifiers from the loop. I've extracted a test case: > http://paste.fedoraproject.org/181199/23025377/raw/
I've managed to squash out the test into a smaller one, directly on the Loop ->watch_io method (rather than involving Notifiers). Now added to LoopTests (so all loops are tested for it), and fixed in Select.pm -- Paul Evans
Subject: rt101919.patch
=== modified file 'lib/IO/Async/Loop/Select.pm' --- lib/IO/Async/Loop/Select.pm 2014-10-17 16:54:33 +0000 +++ lib/IO/Async/Loop/Select.pm 2015-02-14 19:06:11 +0000 @@ -1,7 +1,7 @@ # You may distribute under the terms of either the GNU General Public License # or the Artistic License (the same terms as Perl itself) # -# (C) Paul Evans, 2007-2013 -- leonerd@leonerd.org.uk +# (C) Paul Evans, 2007-2015 -- leonerd@leonerd.org.uk package IO::Async::Loop::Select; @@ -177,7 +177,7 @@ alarm( IO::Async::Loop->WATCHDOG_INTERVAL ) if WATCHDOG_ENABLE; foreach my $fd ( keys %$iowatches ) { - my $watch = $iowatches->{$fd}; + my $watch = $iowatches->{$fd} or next; my $fileno = $watch->[0]->fileno; === modified file 'lib/IO/Async/LoopTests.pm' --- lib/IO/Async/LoopTests.pm 2014-10-17 16:54:33 +0000 +++ lib/IO/Async/LoopTests.pm 2015-02-14 19:06:11 +0000 @@ -1,7 +1,7 @@ # You may distribute under the terms of either the GNU General Public License # or the Artistic License (the same terms as Perl itself) # -# (C) Paul Evans, 2009-2013 -- leonerd@leonerd.org.uk +# (C) Paul Evans, 2009-2015 -- leonerd@leonerd.org.uk package IO::Async::LoopTests; @@ -158,7 +158,7 @@ =cut -use constant count_tests_io => 17; +use constant count_tests_io => 18; sub run_tests_io { { @@ -336,6 +336,28 @@ is( $callcount, 1, 'read/write_ready can cancel each other' ); } + # Check that cross-connected handlers can cancel each other + { + my ( $SA1, $SA2 ) = IO::Async::OS->socketpair or die "Cannot socketpair - $!"; + my ( $SB1, $SB2 ) = IO::Async::OS->socketpair or die "Cannot socketpair - $!"; + $_->blocking( 0 ) for $SA1, $SA2, $SB1, $SB2; + + my @handles = ( $SA1, $SB1 ); + + my $callcount = 0; + $loop->watch_io( + handle => $_, + on_write_ready => sub { + $callcount++; + $loop->unwatch_io( handle => $_, on_write_ready => 1 ) for @handles; + }, + ) for @handles; + + $loop->loop_once( 0.1 ); + + is( $callcount, 1, 'write_ready on crosslinked handles can cancel each other' ); + } + # Check that error conditions that aren't true read/write-ability are still # invoked {
Released in 0.65 -- Paul Evans