| 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 ()) ()) |