Thoughts on async RTS API?
Ben Gamari
ben at well-typed.com
Wed Dec 15 16:05:15 UTC 2021
Cheng Shao <cheng.shao at tweag.io> writes:
> Hi devs,
>
> To invoke Haskell computation in C, we need to call one of rts_eval*
> functions, which enters the scheduler loop, and returns only when the
> specified Haskell thread is finished or killed. We'd like to enhance
> the scheduler and add async variants of the rts_eval* functions, which
> take C callbacks to consume the Haskell thread result, kick off the
> scheduler loop, and the loop is allowed to exit when the Haskell
> thread is blocked. Sync variants of RTS API will continue to work with
> unchanged behavior.
>
> The main intended use case is async foreign calls for the WebAssembly
> target. When an async foreign call is made, the Haskell thread will
> block on an MVar to be fulfilled with the call result. But the
> scheduler will eventually fail to find work due to empty run queue and
> exit with error! We need a way to gracefully exit the scheduler, so
> the RTS API caller can process the async foreign call, fulfill that
> MVar and resume Haskell computation later.
>
> Question I: does the idea of adding async RTS API sound acceptable by
> GHC HQ? To be honest, it's not impossible to workaround lack of async
> RTS API: reuse the awaitEvent() logic in non-threaded RTS, pretend
> each async foreign call reads from a file descriptor and can be
> handled by the POSIX select() function in awaitEvent(). But it'd
> surely be nice to avoid such hacks and do things the principled way.
>
While the idea here sounds reasonable, I'm not sure I quite understand
how this will be used in Asterius's case. Specifically, I would be
worried about the lack of fairness in this scheme: no progress will be
made on any foreign call until all Haskell evaluation has blocked.
Is this really the semantics that you want?
> Question II: how to modify the scheduler loop to implement this
> feature? Straightforward answer seems to be: check some RTS API
> non-blocking flag, if present, allow early exit due to empty run
> queue.
>
`schedule` is already a very large function with loops, gotos,
mutability, and quite complex control flow. I would be reluctant
to add to this complexity without first carrying out some
simplification. Instead of adding yet another bail-out case to the loop,
I would probably rather try to extract the loop body into a new
function. That is, currently `schedule` is of the form:
// Perform work until we are asked to shut down.
Capability *schedule (Capability *initialCapability, Task *task) {
Capability *cap = initialCapability;
while (1) {
scheduleYield(&cap, task);
if (emptyRunQueue(cap)) {
continue;
}
if (shutting_down) {
return cap;
}
StgTSO *t = popRunQueue(cap);
if (! t.can_run_on_capability(cap)) {
// Push back on the run queue and loop around again to
// yield the capability to the appropriate task
pushOnRunQueue(cap, t);
continue;
}
runMutator(t);
if (needs_gc) {
scheduleDoGC();
}
}
}
I might rather extract this into something like:
enum ScheduleResult {
NoWork, // There was no work to do
PerformedWork, // Ran precisely one thread
Yield, // The next thread scheduled to run cannot run on the
// given capability; yield.
ShuttingDown, // We were asked to shut down
}
// Schedule at most one thread once
ScheduleResult scheduleOnce (Capability **cap, Task *task) {
if (emptyRunQueue(cap)) {
return NoWork;
}
if (shutting_down) {
return ShuttingDown;
}
StgTSO *t = popRunQueue(cap);
if (! t.can_run_on_capability(cap)) {
pushOnRunQueue(cap, t);
return Yield;
}
runMutator(t);
if (needs_gc) {
scheduleDoGC();
}
return PerformedWork;
}
This is just a sketch but I hope it's clear that with something like
this this you can easily implement the existing `schedule` function, as
well as your asynchronous variant.
Cheers,
- Ben
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 905 bytes
Desc: not available
URL: <http://mail.haskell.org/pipermail/ghc-devs/attachments/20211215/0f7419b0/attachment.sig>
More information about the ghc-devs
mailing list