--- Coro/Coro.pm 2008/06/15 22:31:33 1.192 +++ Coro/Coro.pm 2008/11/20 06:32:55 1.229 @@ -18,6 +18,7 @@ cede; # and again # use locking + use Coro::Semaphore; my $lock = new Coro::Semaphore; my $locked; @@ -57,7 +58,7 @@ package Coro; -use strict; +use strict qw(vars subs); no warnings "uninitialized"; use Coro::State; @@ -68,7 +69,7 @@ our $main; # main coroutine our $current; # current coroutine -our $VERSION = 4.743; +our $VERSION = 5.0; our @EXPORT = qw(async async_pool cede schedule terminate current unblock_sub); our %EXPORT_TAGS = ( @@ -83,17 +84,17 @@ This variable stores the coroutine object that represents the main program. While you cna C it and do most other things you can do to coroutines, it is mainly useful to compare again C<$Coro::current>, to see -wether you are running in the main program or not. +whether you are running in the main program or not. =cut -$main = new Coro; +# $main is now being initialised by Coro::State =item $Coro::current The coroutine object representing the current coroutine (the last coroutine that the Coro scheduler switched to). The initial value is -C<$main> (of course). +C<$Coro::main> (of course). This variable is B I. You can take copies of the value stored in it and use it as any other coroutine object, but you must @@ -101,14 +102,6 @@ =cut -$main->{desc} = "[main::]"; - -# maybe some other module used Coro::Specific before... -$main->{_specific} = $current->{_specific} - if $current; - -_set_current $main; - sub current() { $current } # [DEPRECATED] =item $Coro::idle @@ -153,13 +146,13 @@ # call all destruction callbacks $_->(@{$self->{_status}}) - for @{(delete $self->{_on_destroy}) || []}; + for @{ delete $self->{_on_destroy} || [] }; } # this coroutine is necessary because a coroutine # cannot destroy itself. -my @destroy; -my $manager; +our @destroy; +our $manager; $manager = new Coro sub { while () { @@ -169,7 +162,7 @@ &schedule; } }; -$manager->desc ("[coro manager]"); +$manager->{desc} = "[coro manager]"; $manager->prio (PRIO_MAX); =back @@ -221,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 completely 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 @@ -236,12 +229,12 @@ disabled, the description will be reset and the default output filehandle gets restored, so you can change all these. Otherwise the coroutine will be re-used "as-is": most notably if you change other per-coroutine global -stuff such as C<$/> you I to revert that change, which is most -simply done by using local as in: C< local $/ >. +stuff such as C<$/> you I revert that change, which is most +simply done by using local as in: C<< local $/ >>. -The pool size is limited to C<8> idle coroutines (this can be adjusted by -changing $Coro::POOL_SIZE), and there can be as many non-idle coros as -required. +The idle pool size is limited to C<8> idle coroutines (this can be +adjusted by changing $Coro::POOL_SIZE), but there can be as many non-idle +coros as required. If you are concerned about pooled coroutines growing a lot because a single C used a lot of stackspace you can e.g. C{_invoke} = [@_]; - $coro->ready; - - $coro -} - =back =head2 STATIC METHODS @@ -309,27 +284,10 @@ a variable, then arrange for some callback of yours to call C<< ->ready >> on that once some event happens, and last you call C to put yourself to sleep. Note that a lot of things can wake your coroutine up, -so you need to check wether the event indeed happened, e.g. by storing the +so you need to check whether the event indeed happened, e.g. by storing the status in a variable. -The canonical way to wait on external events is this: - - { - # remember current coroutine - my $current = $Coro::current; - - # register a hypothetical event handler - on_event_invoke sub { - # wake up sleeping coroutine - $current->ready; - undef $current; - }; - - # call schedule until event occurred. - # in case we are woken up for other reasons - # (current still defined), loop. - Coro::schedule while $current; - } +See B, below, for some ways to wait for callbacks. =item cede @@ -358,13 +316,16 @@ usually only one of them should inherit the running coroutines. Note that while this will try to free some of the main programs resources, -you cnanot free all of them, so if a coroutine that is not the main +you cannot free all of them, so if a coroutine that is not the main program calls this function, there will be some one-time resource leak. =cut sub terminate { - $current->cancel (@_); + $current->{_status} = [@_]; + push @destroy, $current; + $manager->ready; + do { &schedule } while 1; } sub killall { @@ -395,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 @@ -417,7 +372,7 @@ =item $is_ready = $coroutine->is_ready -Return wether the coroutine is currently the ready queue or not, +Return whether the coroutine is currently the ready queue or not, =item $coroutine->cancel (arg...) @@ -429,17 +384,57 @@ 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 +inside the coroutine at the next convenient point in time. Otherwise +clears the exception object. + +Coro will check for the exception each time a schedule-like-function +returns, i.e. after each C, C, C<< Coro::Semaphore->down +>>, C<< Coro::Handle->readable >> and so on. Most of these functions +detect this case and return early in case an exception is pending. + +The exception object will be thrown "as is" with the specified scalar in +C<$@>, i.e. if it is a string, no line number or newline will be appended +(unlike with C). + +This can be used as a softer means than C to ask a coroutine to +end itself, although there is no guarantee that the exception will lead to +termination, and if the exception isn't caught it might well end the whole +program. + +You might also think of C as being the moral equivalent of +Cing a coroutine with a signal (in this case, a scalar). + =item $coroutine->join Wait until the coroutine terminates and return any values given to the @@ -510,26 +505,11 @@ =item $olddesc = $coroutine->desc ($newdesc) Sets (or gets in case the argument is missing) the description for this -coroutine. This is just a free-form string you can associate with a coroutine. - -This method simply sets the C<< $coroutine->{desc} >> member to the given string. You -can modify this member directly if you wish. - -=item $coroutine->throw ([$scalar]) - -If C<$throw> is specified and defined, it will be thrown as an exception -inside the coroutine at the next convinient point in time (usually after -it gains control at the next schedule/transfer/cede). Otherwise clears the -exception object. - -The exception object will be thrown "as is" with the specified scalar in -C<$@>, i.e. if it is a string, no line number or newline will be appended -(unlike with C). +coroutine. This is just a free-form string you can associate with a +coroutine. -This can be used as a softer means than C to ask a coroutine to -end itself, although there is no guarentee that the exception will lead to -termination, and if the exception isn't caught it might well end the whole -program. +This method simply sets the C<< $coroutine->{desc} >> member to the given +string. You can modify this member directly if you wish. =cut @@ -631,17 +611,17 @@ 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 } }; -$unblock_scheduler->desc ("[unblock_sub scheduler]"); +$unblock_scheduler->{desc} = "[unblock_sub scheduler]"; sub unblock_sub(&) { my $cb = shift; @@ -652,19 +632,129 @@ } } +=item $cb = Coro::rouse_cb + +Create and return a "rouse callback". That's a code reference that, when +called, will save its arguments and notify the owner coroutine of the +callback. + +See the next function. + +=item @args = Coro::rouse_wait [$cb] + +Wait for the specified rouse callback (or the last one tht was created in +this coroutine). + +As soon as the callback is invoked (or when the calback was invoked before +C), it will return a copy of the arguments originally passed +to the rouse callback. + +See the section B for an actual usage example. + =back =cut 1; +=head1 HOW TO WAIT FOR A CALLBACK + +It is very common for a coroutine to wait for some callback to be +called. This occurs naturally when you use coroutines in an otherwise +event-based program, or when you use event-based libraries. + +These typically register a callback for some event, and call that callback +when the event occured. In a coroutine, however, you typically want to +just wait for the event, simplyifying things. + +For example C<< AnyEvent->child >> registers a callback to be called when +a specific child has exited: + + my $child_watcher = AnyEvent->child (pid => $pid, cb => sub { ... }); + +But from withina coroutine, you often just want to write this: + + my $status = wait_for_child $pid; + +Coro offers two functions specifically designed to make this easy, +C and C. + +The first function, C, generates and returns a callback that, +when invoked, will save it's arguments and notify the coroutine that +created the callback. + +The second function, C, waits for the callback to be called +(by calling C to go to sleep) and returns the arguments +originally passed to the callback. + +Using these functions, it becomes easy to write the C +function mentioned above: + + sub wait_for_child($) { + my ($pid) = @_; + + my $watcher = AnyEvent->child (pid => $pid, cb => Coro::rouse_cb); + + my ($rpid, $rstatus) = Coro::rouse_wait; + $rstatus + } + +In the case where C and C are not flexible enough, +you can roll your own, using C: + + sub wait_for_child($) { + my ($pid) = @_; + + # store the current coroutine in $current, + # and provide result variables for the closure passed to ->child + my $current = $Coro::current; + my ($done, $rstatus); + + # pass a closure to ->child + my $watcher = AnyEvent->child (pid => $pid, cb => sub { + $rstatus = $_[1]; # remember rstatus + $done = 1; # mark $rstatus as valud + }); + + # wait until the closure has been called + schedule while !$done; + + $rstatus + } + + =head1 BUGS/LIMITATIONS +=over 4 + +=item fork with pthread backend + +When Coro is compiled using the pthread backend (which isn't recommended +but required on many BSDs as their libcs are completely broken), then +coroutines will not survive a fork. There is no known workaround except to +fix your libc and use a saner backend. + +=item perl process emulation ("threads") + This module is not perl-pseudo-thread-safe. You should only ever use this module from the same thread (this requirement might be removed in the future to allow per-thread schedulers, but Coro::State does not yet allow -this). I recommend disabling thread support and using processes, as this -is much faster and uses less memory. +this). I recommend disabling thread support and using processes, as having +the windows process emulation enabled under unix roughly halves perl +performance, even when not used. + +=item coroutine switching not signal safe + +You must not switch to another coroutine from within a signal handler +(only relevant with %SIG - most event libraries provide safe signals). + +That means you I call any function that might "block" the +current coroutine - C, C C<< Coro::Semaphore->down >> or +anything that calls those. Everything else, including calling C, +works. + +=back + =head1 SEE ALSO