Copyright | (c) 2014 Galois Inc. |
---|---|
Safe Haskell | None |
Language | Haskell2010 |
Ivory.Language.Coroutine
Contents
Description
This is an implementation of coroutines in Ivory. These coroutines:
- may be suspended and resumed,
- are parametrized over any memory-area type (
Area
), - cannot return values, but can receive values when they are resumed (though this is an incidental detail of the current implementation),
- for now, can have only one instance executing at once, given a particular coroutine name and Ivory module.
Synopsis
- data Coroutine a = Coroutine {
- coroutineName :: String
- coroutineRun :: forall eff s s'. GetAlloc eff ~ Scope s' => IBool -> ConstRef s a -> Ivory eff ()
- coroutineDef :: ModuleDef
- newtype CoroutineBody a = CoroutineBody (forall s1 s2. (forall b. Ivory (Effects (Returns ()) b (Scope s2)) (Ref s1 a)) -> Ivory (ProcEffects s2 ()) ())
- coroutine :: forall a. IvoryArea a => String -> CoroutineBody a -> Coroutine a
Usage Notes
The coroutine itself is presented as a function which has one argument,
yield
. yield
suspends the coroutine's execution at the point of usage.
coroutineRun
(given an argument of false
) then resumes the suspended
coroutine at that point, passing in a value in the process.
Implementation Notes
This implementation handles a coroutine in the form of a single contiguous block of Ivory code. It turns this block into a single large C function, breaking it up into an initialization portion and a series of branches inside an infinite loop. Each branch represents a resume and suspend point within that block.
It was mentioned that yield
suspends a coroutine for later resumption.
The state of the computation to be resumed later - that is, its
continuation - is stored in a C struct, not visible to the outer Ivory code,
but denoted internally with a suffix of _continuation
. This C struct
contains a state variable and every local variable that is created.
At each yield
, after collecting the current computation state into the
continuation, the C function breaks out of its loop and returns.
The yield
action is implemented as a sort of pseudo-function call which is
given a purposely-invalid name (see yieldName
). This Ivory call does not
become an actual function call in generated code, but rather, the code is
suspended right there. (See the extractLocals
and addYield
functions.)
The pseudo-function call returns a ConstRef
to the coroutine's type. Of
course, no actual function call exists, but the action itself still returns
something - hence, Ivory code is able to refer to the return value of a
yield
. Dereferences to it via deref
are turned to references to the
continuation struct.
As this yield
action is an Ivory effect, it can be passed at the Haskell
level, but it cannot be passed as a C value. (If one could hypothetically run
procPtr
on it, then one could pass it around as a value, but any attempt to
call it outside of the same coroutine would result in either an invalid
function call, or a suspend & return of a different coroutine.)
Concrete representation of a coroutine; use coroutine
to produce one.
Constructors
Coroutine | |
Fields
|
newtype CoroutineBody a Source #
The definition of a coroutine body, in the form of a function taking one
argument: an Ivory effect that is the yield
action which suspends the
coroutine, and sets the point at which coroutineRun
resumes it, passing a
value.
Constructors
CoroutineBody (forall s1 s2. (forall b. Ivory (Effects (Returns ()) b (Scope s2)) (Ref s1 a)) -> Ivory (ProcEffects s2 ()) ()) |