--- Coro/Coro.pm 2011/04/30 05:20:03 1.293 +++ Coro/Coro.pm 2011/08/03 14:52:18 1.304 @@ -18,7 +18,6 @@ cede; # and again # use locking - use Coro::Semaphore; my $lock = new Coro::Semaphore; my $locked; @@ -92,9 +91,9 @@ This creates a new coro thread and puts it into the ready queue, meaning it will run as soon as the CPU is free for it. -C will return a coro object - you can store this for future -reference or ignore it, the thread itself will keep a reference to it's -thread object - threads are alive on their own. +C will return a Coro object - you can store this for future +reference or ignore it - a thread that is running, ready to run or waiting +for some event is alive on it's own. Another way to create a thread is to call the C constructor with a code-reference: @@ -133,7 +132,7 @@ instead), but it will give up the CPU regularly because it waits for external events. -As long as a coro thread runs, it's coro object is available in the global +As long as a coro thread runs, its Coro object is available in the global variable C<$Coro::current>. The low-level way to give up the CPU is to call the scheduler, which @@ -198,26 +197,43 @@ Coro::terminate "return value 1", "return value 2"; }; -And yet another way is to C<< ->cancel >> the coro thread from another -thread: +And yet another way is to C<< ->cancel >> (or C<< ->safe_cancel >>) the +coro thread from another thread: my $coro = async { exit 1; }; - $coro->cancel; # an also accept values for ->join to retrieve + $coro->cancel; # also accepts values for ->join to retrieve Cancellation I be dangerous - it's a bit like calling C without actually exiting, and might leave C libraries and XS modules in a weird state. Unlike other thread implementations, however, Coro is exceptionally safe with regards to cancellation, as perl will always be in a consistent -state. +state, and for those cases where you want to do truly marvellous things +with your coro while it is being cancelled - that is, make sure all +cleanup code is executed from the thread being cancelled - there is even a +C<< ->safe_cancel >> method. So, cancelling a thread that runs in an XS event loop might not be the best idea, but any other combination that deals with perl only (cancelling when a thread is in a C method or an C for example) is safe. +Lastly, a coro thread object that isn't referenced is C<< ->cancel >>'ed +automatically - just like other objects in Perl. This is not such a common +case, however - a running thread is referencedy b C<$Coro::current>, a +thread ready to run is referenced by the ready queue, a thread waiting +on a lock or semaphore is referenced by being in some wait list and so +on. But a thread that isn't in any of those queues gets cancelled: + + async { + schedule; # cede to other coros, don't go into the ready queue + }; + + cede; + # now the async above is destroyed, as it is not referenced by anything. + =item 5. Cleanup Threads will allocate various resources. Most but not all will be returned @@ -250,7 +266,8 @@ }; The C function comes in handy for any custom cleanup you -might want to do: +might want to do (but you cannot switch to other coroutines form those +code blocks): async { my $window = new Gtk2::Window "toplevel"; @@ -273,16 +290,13 @@ =item 6. Viva La Zombie Muerte -Even after a thread has terminated and cleaned up it's resources, the coro -object still is there and stores the return values of the thread. Only in -this state will the coro object be "reference counted" in the normal perl -sense: the thread code keeps a reference to it when it is active, but not -after it has terminated. +Even after a thread has terminated and cleaned up its resources, the Coro +object still is there and stores the return values of the thread. -The means the coro object gets freed automatically when the thread has +The means the Coro object gets freed automatically when the thread has terminated and cleaned up and there arenot other references. -If there are, the coro object will stay around, and you can call C<< +If there are, the Coro object will stay around, and you can call C<< ->join >> as many times as you wish to retrieve the result values: async { @@ -330,7 +344,7 @@ our $main; # main coro our $current; # current coro -our $VERSION = 5.372; +our $VERSION = 6.04; our @EXPORT = qw(async async_pool cede schedule terminate current unblock_sub rouse_cb rouse_wait); our %EXPORT_TAGS = ( @@ -712,6 +726,23 @@ against spurious wakeups, and the one in the Coro family certainly do that. +=item $state->is_new + +Returns true iff this Coro object is "new", i.e. has never been run +yet. Those states basically consist of only the code reference to call and +the arguments, but consumes very little other resources. New states will +automatically get assigned a perl interpreter when they are transfered to. + +=item $state->is_zombie + +Returns true iff the Coro object has been cancelled, i.e. +it's resources freed because they were C'ed, C'd, +C'ed or simply went out of scope. + +The name "zombie" stems from UNIX culture, where a process that has +exited and only stores and exit status and no other resources is called a +"zombie". + =item $is_ready = $coro->is_ready Returns true iff the Coro object is in the ready queue. Unless the Coro @@ -730,20 +761,79 @@ =item $coro->cancel (arg...) -Terminates the given Coro object and makes it return the given arguments as +Terminates the given Coro thread and makes it return the given arguments as status (default: an empty list). Never returns if the Coro is the current Coro. -The arguments are not copied, but instead will be referenced directly -(e.g. if you pass C<$var> and after the call change that variable, then -you might change the return values passed to e.g. C, so don't do -that). +This is a rather brutal way to free a coro, with some limitations - if +the thread is inside a C callback that doesn't expect to be canceled, +bad things can happen, or if the cancelled thread insists on running +complicated cleanup handlers that rely on its thread context, things will +not work. + +Any cleanup code being run (e.g. from C blocks) will be run without +a thread context, and is not allowed to switch to other threads. On the +plus side, C<< ->cancel >> will always clean up the thread, no matter +what. If your cleanup code is complex or you want to avoid cancelling a +C-thread that doesn't know how to clean up itself, it can be better to C<< +->throw >> an exception, or use C<< ->safe_cancel >>. + +The arguments to C<< ->cancel >> are not copied, but instead will +be referenced directly (e.g. if you pass C<$var> and after the call +change that variable, then you might change the return values passed to +e.g. C, so don't do that). The resources of the Coro are usually freed (or destructed) before this call returns, but this can be delayed for an indefinite amount of time, as in some cases the manager thread has to run first to actually destruct the Coro object. +=item $coro->safe_cancel ($arg...) + +Works mostly like C<< ->cancel >>, but is inherently "safer", and +consequently, can fail with an exception in cases the thread is not in a +cancellable state. + +This method works a bit like throwing an exception that cannot be caught +- specifically, it will clean up the thread from within itself, so +all cleanup handlers (e.g. C blocks) are run with full thread +context and can block if they wish. The downside is that there is no +guarantee that the thread can be cancelled when you call this method, and +therefore, it might fail. It is also considerably slower than C or +C. + +A thread is in a safe-cancellable state if it either hasn't been run yet, +or it has no C context attached and is inside an SLF function. + +The latter two basically mean that the thread isn't currently inside a +perl callback called from some C function (usually via some XS modules) +and isn't currently executing inside some C function itself (via Coro's XS +API). + +This call returns true when it could cancel the thread, or croaks with an +error otherwise (i.e. it either returns true or doesn't return at all). + +Why the weird interface? Well, there are two common models on how and +when to cancel things. In the first, you have the expectation that your +coro thread can be cancelled when you want to cancel it - if the thread +isn't cancellable, this would be a bug somewhere, so C<< ->safe_cancel >> +croaks to notify of the bug. + +In the second model you sometimes want to ask nicely to cancel a thread, +but if it's not a good time, well, then don't cancel. This can be done +relatively easy like this: + + if (! eval { $coro->safe_cancel }) { + warn "unable to cancel thread: $@"; + } + +However, what you never should do is first try to cancel "safely" and +if that fails, cancel the "hard" way with C<< ->cancel >>. That makes +no sense: either you rely on being able to execute cleanup code in your +thread context, or you don't. If you do, then C<< ->safe_cancel >> is the +only way, and if you don't, then C<< ->cancel >> is always faster and more +direct. + =item $coro->schedule_to Puts the current coro to sleep (like C), but instead @@ -771,17 +861,18 @@ 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. +>>, C<< Coro::Handle->readable >> and so on. Most of those functions (all +that are part of Coro itself) 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 coro 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. +This can be used as a softer means than either C or Cto ask a coro 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 coro with a signal (in this case, a scalar). @@ -793,25 +884,6 @@ from multiple threads, and all will be resumed and given the status return once the C<$coro> terminates. -=cut - -sub join { - my $self = shift; - - unless ($self->{_status}) { - my $current = $current; - - push @{$self->{_on_destroy}}, sub { - $current->ready; - undef $current; - }; - - &schedule while $current; - } - - wantarray ? @{$self->{_status}} : $self->{_status}[0]; -} - =item $coro->on_destroy (\&cb) Registers a callback that is called when this coro thread gets destroyed, @@ -822,14 +894,6 @@ There can be any number of C callbacks per coro, and there is no way currently to remove a callback once added. -=cut - -sub on_destroy { - my ($self, $cb) = @_; - - push @{ $self->{_on_destroy} }, $cb; -} - =item $oldprio = $coro->prio ($newprio) Sets (or gets, if the argument is missing) the priority of the @@ -1110,6 +1174,9 @@ the windows process emulation enabled under unix roughly halves perl performance, even when not used. +Attempts to use threads created in another emulated process will crash +("cleanly", with a null pointer exception). + =item coro switching is not signal safe You must not switch to another coro from within a signal handler (only