--- Coro/Coro.pm 2008/11/19 16:01:32 1.226 +++ Coro/Coro.pm 2008/11/21 06:02:07 1.233 @@ -69,7 +69,7 @@ our $main; # main coroutine our $current; # current coroutine -our $VERSION = 5.0; +our $VERSION = "5.0"; our @EXPORT = qw(async async_pool cede schedule terminate current unblock_sub); our %EXPORT_TAGS = ( @@ -137,18 +137,6 @@ Carp::croak ("FATAL: deadlock detected"); }; -sub _cancel { - my ($self) = @_; - - # free coroutine data and mark as destructed - $self->_destroy - or return; - - # call all destruction callbacks - $_->(@{$self->{_status}}) - for @{ delete $self->{_on_destroy} || [] }; -} - # this coroutine is necessary because a coroutine # cannot destroy itself. our @destroy; @@ -156,7 +144,7 @@ $manager = new Coro sub { while () { - (shift @destroy)->_cancel + Coro::_cancel shift @destroy while @destroy; &schedule; @@ -214,9 +202,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 @@ -239,45 +227,25 @@ If you are concerned about pooled coroutines growing a lot because a single C used a lot of stackspace you can e.g. C once per second or so to slowly replenish the pool. In -addition to that, when the stacks used by a handler grows larger than 16kb +addition to that, when the stacks used by a handler grows larger than 32kb (adjustable via $Coro::POOL_RSS) it will also be destroyed. =cut our $POOL_SIZE = 8; -our $POOL_RSS = 16 * 1024; +our $POOL_RSS = 32 * 1024; 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 @@ -341,13 +309,6 @@ =cut -sub terminate { - $current->{_status} = [@_]; - push @destroy, $current; - $manager->ready; - do { &schedule } while 1; -} - sub killall { for (Coro::State::list) { $_->cancel @@ -413,6 +374,25 @@ } } +=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 @@ -520,6 +500,11 @@ $old; } +sub transfer { + require Carp; + Carp::croak ("You must not call ->transfer on Coro objects. Use Coro::State objects or the ->schedule_to method. Caught"); +} + =back =head2 GLOBAL FUNCTIONS @@ -612,12 +597,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 }