--- cvsroot/Coro/Coro.pm 2011/05/10 19:55:48 1.295 +++ cvsroot/Coro/Coro.pm 2014/02/02 03:26:06 1.321 @@ -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,8 +197,8 @@ Coro::terminate "return value 1", "return value 2"; }; -And yet another way is to C<< ->cancel >> (or C<< ->safe_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; @@ -221,6 +220,43 @@ 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 @@ -248,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"; @@ -276,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"; @@ -333,7 +368,7 @@ our $main; # main coro our $current; # current coro -our $VERSION = 5.372; +our $VERSION = 6.33; our @EXPORT = qw(async async_pool cede schedule terminate current unblock_sub rouse_cb rouse_wait); our %EXPORT_TAGS = ( @@ -348,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. @@ -715,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 @@ -740,7 +792,7 @@ 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 it'S thread context, things will +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 @@ -856,25 +908,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, @@ -883,15 +916,7 @@ not> die, under any circumstances. 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; -} +currently no way to remove a callback once added. =item $oldprio = $coro->prio ($newprio) @@ -928,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 { @@ -1107,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 @@ -1123,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) = @_; @@ -1143,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 @@ -1173,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