diff --git a/README.md b/README.md index 2358805..afb7f58 100644 --- a/README.md +++ b/README.md @@ -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.