--- cvsroot/Coro/Coro.pm 2001/09/02 01:03:53 1.32 +++ cvsroot/Coro/Coro.pm 2001/10/28 17:00:05 1.40 @@ -34,11 +34,13 @@ package Coro; +no warnings qw(uninitialized); + use Coro::State; use base Exporter; -$VERSION = 0.49; +$VERSION = 0.51; @EXPORT = qw(async cede schedule terminate current); %EXPORT_TAGS = ( @@ -116,9 +118,20 @@ # this coroutine is necessary because a coroutine # cannot destroy itself. my @destroy; -my $manager = new Coro sub { +my $manager; +$manager = new Coro sub { while() { - delete ((pop @destroy)->{_coro_state}) while @destroy; + # by overwriting the state object with the manager we destroy it + # while still being able to schedule this coroutine (in case it has + # been readied multiple times. this is harmless since the manager + # can be called as many times as neccessary and will always + # remove itself from the runqueue + while (@destroy) { + my $coro = pop @destroy; + $coro->{status} ||= []; + $_->ready for @{delete $coro->{join} || []}; + $coro->{_coro_state} = $manager->{_coro_state}; + } &schedule; } }; @@ -170,7 +183,7 @@ =cut -=item terminate +=item terminate [arg...] Terminates the current process. @@ -179,6 +192,7 @@ =cut sub terminate { + $current->{status} = [@_]; $current->cancel; &schedule; die; # NORETURN @@ -197,8 +211,9 @@ =item new Coro \&sub [, @args...] Create a new process and return it. When the sub returns the process -automatically terminates. To start the process you must first put it into -the ready queue by calling the ready method. +automatically terminates as if C with the returned values were +called. To start the process you must first put it into the ready queue by +calling the ready method. The coderef you submit MUST NOT be a closure that refers to variables in an outer scope. This does NOT work. Pass arguments into it instead. @@ -218,7 +233,7 @@ =item $process->ready -Put the current process into the ready queue. +Put the given process into the ready queue. =cut @@ -231,6 +246,24 @@ sub cancel { push @destroy, $_[0]; $manager->ready; + &schedule if $current == $_[0]; +} + +=item $process->join + +Wait until the coroutine terminates and return any values given to the +C function. C can be called multiple times from multiple +processes. + +=cut + +sub join { + my $self = shift; + unless ($self->{status}) { + push @{$self->{join}}, $current; + &schedule; + } + wantarray ? @{$self->{status}} : $self->{status}[0]; } =item $oldprio = $process->prio($newprio) @@ -281,14 +314,8 @@ =head1 BUGS/LIMITATIONS - - could be faster, especially when the core would introduce special - support for coroutines (like it does for threads). - - there is still a memleak on coroutine termination that I could not - identify. Could be as small as a single SV. - - this module is not well-tested. - - if variables or arguments "disappear" (become undef) or become - corrupted please contact the author so he cen iron out the - remaining bugs. + - you must make very sure that no coro is still active on global destruction. + very bad things might happen otherwise (usually segfaults). - this module is not thread-safe. You must only ever use this module from the same thread (this requirement might be loosened in the future to allow per-thread schedulers, but Coro::State does not yet allow this).