document coroutines

Ondřej Hruška 3 years ago
parent af52270a29
commit 5a0e370589
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 72

@ -286,7 +286,77 @@ It can also be written like this:
## Coroutines
Croissant implements something that could be called "pre-emptive coroutines". They do not provide any performance gain,
but add asynchronicity to the program, and can work as generators!
There is no true parallelism, it is difficult to implement safely and efficiently with a global state.
### Spawning
*Any procedure can be used as a coroutine.*
A coroutine is created using the `spawn` instruction, which produces an object handle.
(spawn r0 do_stuff 1 2 3)
At this point, the program is evenly divided between the original and the coroutine "thread".
The spawned coroutine is scheduled to run immediately after being spawned.
### Task switching
Coroutines take turns to execute the program. The scheduling interval can be configured.
Control can be given up using the `yield` instruction; for example, when waiting for a mutex. This happens automatically when
a `sleep` instruction is invoked.
### Race conditions
Take care when working with objects, resources and global registers: you can get race conditions
with coroutines. Use atomic instructions (`cas`, `casXX`, `bfcas`…) to implement synchronization.
The `casXX` instruction is very powerful: you can use one bit of a register as a mutex and the rest of it to store some useful data.
You can also use one register for up to 64 mutexes.
Remember to only use global registers (or buffer items) as mutexes: `g0`-`g15`. Each coroutine has its own set of *regular* registers.
### Using coroutines as generators
A coroutine can "yield a value" by invoking the `yield` instruction with an operand. This can be done any number of times.
(yield r0)
The coroutine is blocked until the value is consumed by someone. To consume a yielded value, read the coroutine object handle:
(spawn r5 foo)
(ld r0 @r5) ; read a yielded value
### Joining a coroutine
Use the `join` instruction with a coroutine object handle to wait for its completion.
A coroutine completes by calling `ret` at its top level. This naturally means that a coroutine can return values!
The returned values are placed in the result registers, just like with the `call` instruction.
(spawn r5 foo)
; ...
(join @r0)
; res0-res15 now contain return values
# Instruction Set
Crsn instruction set is composed of extensions.