Feasibility of native RTS support for continuations?

Simon Marlow marlowsd at gmail.com
Thu Jan 30 08:35:58 UTC 2020


My guess is you can almost do what you want with asynchronous exceptions
but some changes to the RTS would be needed.

There's a bit of code in the IO library that literally looks like this (
https://gitlab.haskell.org/ghc/ghc/blob/master/libraries%2Fbase%2FGHC%2FIO%2FHandle%2FInternals.hs#L175
):

            t <- myThreadId
            throwTo t e
            ... carry on ...

that is, it throws an exception to the current thread using throwTo, and
then there is code to handle what happens if the enclosing thunk is
evaluated after the exception has been thrown.

That is, throwing an exception to the current thread is an IO operation
that returns later! This only works with throwTo, not with throwIO, because
throwIO is a *synchronous* exception that destructively tears down the
stack.

I suppose if you want to pass a value to the thread after resumption you
could do it via an IORef.

But the issue with this is that you can only apply the continuation once:
GHC treats the captured continuation like a thunk, which means that after
evaluating it, it will be updated with its value. But for your purposes you
need to be able to apply it at least twice - once because we want to
continue after shift#, and again when we apply the continuation later.
Somehow the thunks we build this way would need to be marked non-updatable.
Perhaps this could be done with a new primitive `throwToNonUpdatable`
(hopefully with a better name) that creates non-updatable thunks. Also you
might want to optimise the implementation so that it doesn't actually tear
down the stack as it copies it into the heap, so that you could avoid the
need to copy it back from the heap again in shift#.

So that's shift#. What about reset#? I expect it's something like
`unsafeInterleaveIO`, that is it creates a thunk to name the continuation.
You probably also want a `catch` in there, so that we don't tear down more
of the stack than we need to.

Hope this is helpful.

Cheers
Simon


On Thu, 30 Jan 2020 at 00:55, Alexis King <lexi.lambda at gmail.com> wrote:

> > On Jan 29, 2020, at 03:32, Simon Peyton Jones <simonpj at microsoft.com>
> wrote:
> >
> > Suppose a thread happens to be evaluating a pure thunk for (factorial
> 200). […] This stack-freezing stuff is definitely implemented.
>
> That’s fascinating! I had no idea, but your explanation makes sense (as do
> the papers you linked). That is definitely promising, as it seems like many
> of the tricky cases may already be accounted for? I’ll see if I can follow
> the Cmm code well enough to hunt down how it’s implemented.
>
> One other thing I have been thinking about: this is completely
> incompatible with the state hack, isn’t it? That is not a showstopper, of
> course—I do not intend to suggest that continuations be capturable in
> ordinary IO—but it does mean I probably want a way to selectively opt out.
> (But I’ll worry about that if I ever get that far.)
>
> Alexis
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-devs/attachments/20200130/bf5acb0a/attachment.html>


More information about the ghc-devs mailing list