Skip Menu |

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

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

People
Owner: Nobody in particular
Requestors: leonerd-cpan [...] leonerd.org.uk
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: 0.43
Fixed in: 0.44



Subject: Cancelling a timer while it is firing breaks the timequeue
use strict; use warnings; use feature 'say'; use IO::Async::Loop; my $loop = IO::Async::Loop->new; say "Using Loop type " . ref $loop; my $t1; $t1 = $loop->enqueue_timer( delay => 0, code => sub { warn "Cancelled t1 as $t1\n"; $loop->cancel_timer ($t1); undef $t1; warn "t1 fired\n"; } ); warn "Queued t1 as $t1\n"; $loop->enqueue_timer( delay => 0.1, code => sub { warn "t2 fired\n"; } ); warn "Queued t2\n"; $loop->loop_forever; Prints output: Queued t1 as IO::Async::Internals::TimeQueue::Elem=ARRAY(0x18ed720) Queued t2 Cancelled t1 as IO::Async::Internals::TimeQueue::Elem=ARRAY(0x18ed720) t1 fired ^C Expected t1 fired t2 fired -- Paul Evans
Initial investigation suggests it's Timequeue related, as it depends on Loop subclass: $ IO_ASYNC_LOOP=POE perl rt70231.pl Using Loop type IO::Async::Loop::POE Queued t1 as 4 Queued t2 Cancelled t1 as 4 t1 fired t2 fired ^C $ IO_ASYNC_LOOP=Glib perl rt70231.pl Using Loop type IO::Async::Loop::Glib Queued t1 as 2 Queued t2 Cancelled t1 as 2 t1 fired t2 fired ^C $ perl rt70231.pl Using Loop type IO::Async::Loop::Epoll Queued t1 as IO::Async::Internals::TimeQueue::Elem=ARRAY(0x9a01650) Queued t2 Cancelled t1 as IO::Async::Internals::TimeQueue::Elem=ARRAY(0x9a01650) t1 fired ^C -- Paul Evans
Oops. Turns out items off the timequeue were only removed -after- firing them; and then we just presume that the top of the queue happens to be the right element. Removing from the queue before firing the event fixes it. See attached patch + unit tests. -- Paul Evans
Subject: rt70231.patch
=== modified file 'lib/IO/Async/Internals/TimeQueue.pm' --- lib/IO/Async/Internals/TimeQueue.pm 2011-07-26 00:19:12 +0000 +++ lib/IO/Async/Internals/TimeQueue.pm 2011-08-12 12:40:03 +0000 @@ -98,10 +98,10 @@ while( defined( my $top = $heap->top ) ) { last if( $top->time > $now ); + $heap->extract_top; + $top->code->(); $count++; - - $heap->extract_top; } return $count; === modified file 'lib/IO/Async/LoopTests.pm' --- lib/IO/Async/LoopTests.pm 2011-08-04 22:01:14 +0000 +++ lib/IO/Async/LoopTests.pm 2011-08-12 12:35:43 +0000 @@ -381,7 +381,7 @@ =cut -use constant count_tests_timer => 10; +use constant count_tests_timer => 12; sub run_tests_timer { my $done = 0; @@ -441,6 +441,21 @@ time_between { $loop->loop_once while !$done; } 0, 0.1, 'loop_once while waiting for negative interval timer'; + + my $doneA; + my $doneB; + + $id = $loop->enqueue_timer( delay => 1 * AUT, code => sub { + $loop->cancel_timer( $id ); undef $id; + $doneA++; + }); + + $loop->enqueue_timer( delay => 1.1 * AUT, code => sub { $doneB++ } ); + + $loop->loop_once( 1 * AUT ) for 1 .. 3; + + is( $doneA, 1, 'Self-cancelling timer still fires' ); + is( $doneB, 1, 'Other timers still fire after self-cancelling one' ); } =head2 signal
Now released in 0.44 -- Paul Evans