--- Coro/Coro.pm 2008/11/19 05:52:42 1.224 +++ Coro/Coro.pm 2008/11/20 06:32:55 1.229 @@ -151,8 +151,8 @@ # this coroutine is necessary because a coroutine # cannot destroy itself. -my @destroy; -my $manager; +our @destroy; +our $manager; $manager = new Coro sub { while () { @@ -214,9 +214,9 @@ coroutine that might have executed other code already (which can be good or bad :). -On the plus side, this function is faster than creating (and destroying) -a completly new coroutine, so if you need a lot of generic coroutines in -quick successsion, use C, not C. +On the plus side, this function is about twice as fast as creating (and +destroying) a completely new coroutine, so if you need a lot of generic +coroutines in quick successsion, use C, not C. The code block is executed in an C context and a warning will be issued in case of an exception instead of terminating the program, as @@ -249,35 +249,15 @@ our @async_pool; sub pool_handler { - my $cb; - while () { eval { - while () { - _pool_1 $cb; - &$cb; - _pool_2 $cb; - &schedule; - } + &{&_pool_handler} while 1; }; - if ($@) { - last if $@ eq "\3async_pool terminate\2\n"; - warn $@; - } + warn $@ if $@; } } -sub async_pool(&@) { - # this is also inlined into the unblock_scheduler - my $coro = (pop @async_pool) || new Coro \&pool_handler; - - $coro->{_invoke} = [@_]; - $coro->ready; - - $coro -} - =back =head2 STATIC METHODS @@ -342,7 +322,10 @@ =cut sub terminate { - $current->cancel (@_); + $current->{_status} = [@_]; + push @destroy, $current; + $manager->ready; + do { &schedule } while 1; } sub killall { @@ -373,16 +356,10 @@ =cut -sub _run_coro { +sub _terminate { terminate &{+shift}; } -sub new { - my $class = shift; - - $class->SUPER::new (\&_run_coro, @_) -} - =item $success = $coroutine->ready Put the given coroutine into the end of its ready queue (there is one @@ -407,17 +384,34 @@ sub cancel { my $self = shift; - $self->{_status} = [@_]; if ($current == $self) { - push @destroy, $self; - $manager->ready; - &schedule while 1; + terminate @_; } else { + $self->{_status} = [@_]; $self->_cancel; } } +=item $coroutine->schedule_to + +Puts the current coroutine to sleep (like C), but instead +of continuing with the next coro from the ready queue, always switch to +the given coroutine object (regardless of priority etc.). The readyness +state of that coroutine isn't changed. + +This is an advanced method for special cases - I'd love to hear about any +uses for this one. + +=item $coroutine->cede_to + +Like C, but puts the current coroutine into the ready +queue. This has the effect of temporarily switching to the given +coroutine, and continuing some time later. + +This is an advanced method for special cases - I'd love to hear about any +uses for this one. + =item $coroutine->throw ([$scalar]) If C<$throw> is specified and defined, it will be thrown as an exception @@ -617,12 +611,12 @@ our $unblock_scheduler = new Coro sub { while () { while (my $cb = pop @unblock_queue) { - # this is an inlined copy of async_pool - my $coro = (pop @async_pool) || new Coro \&pool_handler; + &async_pool (@$cb); - $coro->{_invoke} = $cb; - $coro->ready; - cede; # for short-lived callbacks, this reduces pressure on the coro pool + # for short-lived callbacks, this reduces pressure on the coro pool + # as the chance is very high that the async_poll coro will be back + # in the idle state when cede returns + cede; } schedule; # sleep well }