Coro::State#
Coro::State - the engine under Coro: Perl-level threads (“coroutines”) with their own call stacks, switched cooperatively.
use Coro;
# Three coroutines take turns: each cede lets the next ready one run.
my @workers = map {
my $id = $_;
async {
for my $step (1 .. 2) {
print "worker $id, step $step\n";
cede;
}
return "worker $id done";
};
} 1 .. 3;
print $_->join, "\n" for @workers; # wait for each, collect its result
# A semaphore makes the others wait while one holds it.
my $lock = Coro::Semaphore->new(1);
my $t = async { my $g = $lock->guard; print "got the lock\n" };
{
my $g = $lock->guard;
cede; # $t runs, and blocks on the lock
print "releasing, ", scalar($lock->waiters), " waiting\n";
}
$t->join;
# The engine underneath: switch between two states by hand.
my ($main, $other);
$other = Coro::State->new(sub { print "in other\n"; $other->transfer($main) });
$main = Coro::State->new;
$main->transfer($other);
print "back in main\n";
prints worker 1, step 1 to worker 3, step 1, then the three step 2 lines, the three done lines, releasing, 1 waiting, got the lock, in other and back in main.
Most programs use Coro and never touch Coro::State directly. Coro::State is the machinery: a coroutine for a sub, and switching from one to another. Coro’s scheduler, its coroutine objects, Coro::Semaphore and Coro::Signal are built on it, and their XS half lives here too.
Each coroutine has its own $_, @_, $@, $/, $1…, $^H and %^H, die and warn hooks ($Coro::State::DIEHOOK and WARNHOOK are the defaults), default output handle, local values and lexicals. A coroutine that switches away from inside a sort block, a tie method, a DESTROY or any other callback keeps a C stack of its own until it gets back out; the size of those stacks is Coro::State::cctx_stacksize, in pointers (default 16384, which is 128 KiB).
This is a native implementation of the XS half of Coro 6.57; its Coro.pm and every Coro::* module are used unchanged. use Coro exports async, async_pool, cede, schedule, terminate, current, unblock_sub, rouse_cb and rouse_wait; the PRIO_* constants and nready on request. Coro::State exports nothing. Coro::State::BACKEND names the stack-switch method: asm on x86-64, sjlj (setjmp/longjmp) elsewhere - what Coro’s own build picks on Linux.
Coroutines: the Coro functions#
async { ... } @argscreates a coroutine running the block with@args, puts it in the ready queue and returns itsCoroobject. Returning from the block ends it; an uncaughtdieends the program, as in the main program.async_pool { ... } @argsis the same with a coroutine from a pool of reused ones: faster, runs the block in aneval(adiewarns), and never terminates, so it is not to be joined.Coro->new(\&sub, @args)creates a coroutine without readying it.cedeputs the current coroutine at the end of the ready queue and runs the next one of the same or higher priority;Coro::cede_notselfcedes to any ready one, whatever its priority.scheduleruns the next ready coroutine without readying the current one: the way to block until something calls->ready.terminate @valuesends the current coroutine with those values.Coro::nreadyis the number of coroutines in the ready queue.rouse_cbreturns a callback;rouse_waitblocks until that callback (or the one passed to it) has been called, and returns the arguments it was called with. They turn a callback API into a blocking call.Coro::on_enter BLOCKandCoro::on_leave BLOCKrun their block whenever the current coroutine is switched to or away from, while the enclosing scope lasts.
The methods of a Coro object $coro:
$coro->readyqueues it; false when it already was.$coro->suspendkeeps the scheduler from running it until$coro->resume.$coro->joinwaits for it to end and returns its values (the block’s return value, or whatterminateorcancelgave).$coro->cancel(@values)ends it at once, from outside;$coro->safe_cancel(@values)ends it from inside, so its cleanup runs in its own context, and dies when it is not in a state where that can be done.$coro->throw($exception)makes it die with$exceptionwhen it next runs.$coro->on_destroy(\&cb)callscbwith its values when it ends.$coro->schedule_toand$coro->cede_toswitch to it directly, bypassing the queue;cede_toreadies the current coroutine first.$coro->prio($new)and$coro->nice($change)set its priority (fromPRIO_MIN, -4, toPRIO_MAX, 3;nicesubtracts) and return the previous one.$coro->is_new,is_ready,is_running,is_suspended,is_zombie(ended) andis_destroyed(the same) report its state.
Coro::Semaphore->new($count) has down (wait until the count is positive, then take one), up, try (take one if available), count, adjust($delta), waiters (the waiting coroutines, or their number in scalar context) and, from Coro’s Perl half, guard. Coro::Signal->new has wait, send (wake one waiter, or the next to wait), broadcast (wake every waiter) and awaited.
Coro::State#
Coro::State->new(\&sub, @args)makes a state that runssubwhen first transferred to;Coro::State->newwith no sub makes an empty one to save the current state in. A sub that returns ends the program.$prev->transfer($next)saves the running state in$prevand continues$next.$state->call(\&code)and$state->eval($string)run code in the context of another state (for debuggers; the code must not switch).$state->swap_defsvandswap_defavexchange the current$_or@_with the state’s;$state->swap_sv(\$var, \$private)makes$varhold$private’s contents whenever that state runs (calling it again with the same two undoes it).$state->canceldestroys the state.$state->throw,is_new,is_zombieare as for Coro objects.$state->rssis the memory its stacks use, in bytes;usecountthe number of transfers to it.Coro::State::enable_times($bool)turns on per-coroutine time accounting and returns the previous setting;$state->timesthen returns its real and CPU seconds.Coro::State::listreturns every state, Coro objects included.$state->trace($flags)traces sub calls and statements in it, asCoro::Debuguses;$state->is_tracedreads the flags.C stacks:
$state->has_cctxsays whether it holds one;Coro::State::force_cctxgives the running state one;Coro::State::cctx_countandcctx_idlecount those in use and cached;cctx_max_idle($n)andcctx_stacksize($n)set the cache size (default 4) and the size of new stacks, each returning the old value.$state->clonedies “Coro::State->clone has not been configured into this installation of Coro”, as in a default Coro build.
The other Coro modules (Coro::Channel, Coro::RWLock, Coro::Specific, Coro::Timer, Coro::AnyEvent, Coro::Handle, Coro::Debug, …) are Coro’s Perl modules, unchanged.
Differences from upstream#
Two, both where perl 5.44 with XS Coro crashes (t/81-xs-native/Coro/390-or-better.t):
Coro::State::is_ready(bless {}, 'X')and the other methods called on a blessed hash that is not a coroutine die “Coro::State object required”, as they do for every other non-coroutine. Coro reads the magic of a hash that has none and crashes.binmode $fh, ':cede'with no interval uses the 0.01-second interval Coro’s layer falls back to. Coro reads the missing argument and crashes.