--- Coro/Coro.pm 2011/04/30 05:17:42 1.292 +++ Coro/Coro.pm 2013/03/06 06:00:08 1.316 @@ -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,66 @@ Coro::terminate "return value 1", "return value 2"; }; -And yet another way is to C<< ->cancel >> the coro thread from another -thread: +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. +Last not least, 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 by +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. + +A slightly embellished example might make it clearer: + + async { + my $guard = Guard::guard { print "destroyed\n" }; + schedule while 1; + }; + + cede; + +Superficially one might not expect any output - since the C +implements an endless loop, the C<$guard> will not be cleaned up. However, +since the thread object returned by C is not stored anywhere, the +thread is initially referenced because it is in the ready queue, when it +runs it is referenced by C<$Coro::current>, but when it calls C, +it gets Ced causing the guard object to be destroyed (see the next +section), and printing it's message. + +If this seems a bit drastic, remember that this only happens when nothing +references the thread anymore, which means there is no way to further +execute it, ever. The only options at this point are leaking the thread, +or cleaning it up, which brings us to... + =item 5. Cleanup Threads will allocate various resources. Most but not all will be returned @@ -245,12 +284,13 @@ async { my $lock_guard = $sem->guard; - # if we reutrn, or die or get cancelled, here, + # if we return, or die or get cancelled, here, # then the semaphore will be "up"ed. }; 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 from those +code blocks): async { my $window = new Gtk2::Window "toplevel"; @@ -273,17 +313,15 @@ =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 -terminated and cleaned up and there arenot other references. +When there are no other references, it will simply be cleaned up and +freed. -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: +If there areany references, the Coro object will stay around, and you +can call C<< ->join >> as many times as you wish to retrieve the result +values: async { print "hi\n"; @@ -330,7 +368,7 @@ our $main; # main coro our $current; # current coro -our $VERSION = 5.372; +our $VERSION = 6.28; our @EXPORT = qw(async async_pool cede schedule terminate current unblock_sub rouse_cb rouse_wait); our %EXPORT_TAGS = ( @@ -345,7 +383,7 @@ =item $Coro::main This variable stores the Coro object that represents the main -program. While you cna C it and do most other things you can do to +program. While you can C it and do most other things you can do to coro, it is mainly useful to compare again C<$Coro::current>, to see whether you are running in the main program or not. @@ -712,6 +750,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 +785,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 +885,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,40 +908,15 @@ 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, -but before it is joined. The callback gets passed the terminate arguments, -if any, and I die, under any circumstances. - -There can be any number of C callbacks per coro. - -=cut - -sub on_destroy { - my ($self, $cb) = @_; +that is, after it's resources have been freed but before it is joined. The +callback gets passed the terminate/cancel arguments, if any, and I die, under any circumstances. - push @{ $self->{_on_destroy} }, $cb; -} +There can be any number of C callbacks per coro, and there is +no way currently to remove a callback once added. =item $oldprio = $coro->prio ($newprio) @@ -863,7 +953,7 @@ This method simply sets the C<< $coro->{desc} >> member to the given string. You can modify this member directly if you wish, and in fact, this -is often preferred to indicate major processing states that cna then be +is often preferred to indicate major processing states that can then be seen for example in a L session: sub my_long_function { @@ -1042,7 +1132,7 @@ my $status = wait_for_child $pid; Coro offers two functions specifically designed to make this easy, -C and C. +C and C. The first function, C, generates and returns a callback that, when invoked, will save its arguments and notify the coro that @@ -1058,14 +1148,14 @@ sub wait_for_child($) { my ($pid) = @_; - my $watcher = AnyEvent->child (pid => $pid, cb => Coro::rouse_cb); + my $watcher = AnyEvent->child (pid => $pid, cb => rouse_cb); - my ($rpid, $rstatus) = Coro::rouse_wait; + my ($rpid, $rstatus) = rouse_wait; $rstatus } In the case where C and C are not flexible enough, -you can roll your own, using C: +you can roll your own, using C and C: sub wait_for_child($) { my ($pid) = @_; @@ -1078,7 +1168,8 @@ # pass a closure to ->child my $watcher = AnyEvent->child (pid => $pid, cb => sub { $rstatus = $_[1]; # remember rstatus - $done = 1; # mark $rstatus as valud + $done = 1; # mark $rstatus as valid + $current->ready; # wake up the waiting thread }); # wait until the closure has been called @@ -1108,6 +1199,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