-
Notifications
You must be signed in to change notification settings - Fork 1
Home
-
Fast, only does what it really needs to do
-
Coroutines can start other coroutines
-
Interrupt routines can start coroutines
-
Caller can pass data to coroutine, and coroutine can pass data back to caller.
-
Can be used as non-preemptive multithreading, step-by-step function execution, functional programming, or however you want to use it.
-
Sub-coroutine can yield value towards its parent coroutine's caller, instead of to its parent coroutine. This is not recommended because it's pretty much the definition of spaghetti code. Almost no other coroutine implementations have this option available.
-
Requires your system to have a
malloc
function that takes anint
and returns a pointer. -
Only tested on ARMv7 Thumb-2
-
You must manually configure stack size when starting a new coroutine
-
Coroutines cannot safely use
return;
statements, they must usereturn co;
(whereco
is theCoroutine*
) or call the CoReturn function.
CoInit
runs in 16 instructions + 1 call to malloc
CoRun
and CoYield
run in 9 instructions.
CoReturn
runs in 6 instructions.
-
Place a link to your system's
malloc
function incoroutines_asm.s
. Detailed instructions are in that file's comments. -
Compile
coroutines.c
andcoroutines_asm.s
together with your project. -
#include "coroutines.h"
where you want to use coroutines.
The 4 functions implemented in ASM (CoInit, CoYield, CoRun and CoReturn) will preserve the caller's r4-r14
. The caller must preserve his own r0-r3
. (this is standard ARM calling convention, most likely your compiler already does this)
Name | Argument 0 | Argument 1 | Return value | Description |
---|---|---|---|---|
CoInit | Coroutine* (funcPtr)(uint32 runValue, Coroutine co)); | uint32 stackSizeBytes | Coroutine* | Allocates memory for and initializes a new coroutine. Returns a pointer to the allocated Coroutine. It is your responsibility to make sure you allocate enough stack space for your coroutine function and its function calls. |
CoRun | uint32 runValue | Coroutine* | uint32 yieldValue | Start or resume execution of a coroutine. If this is the first call to CoRun, the runValue will be the first argument to the coroutine function. If this is not the first call to CoRun, the runValue will be the return value of CoYield. You may only call CoRun more than once if CoHasReturned returns false. |
CoYield | uint32 yieldValue | Coroutine* | uint32 runValue | Pause execution of the current coroutine and resume execution of the CoRun caller. The yieldValue will be the return value of CoRun. |
CoReturn | Coroutine* | Finish execution of the current coroutine. Same as: return co; After calling CoReturn, the CoHasReturned function will return true, and the return value of CoRun should not be used. |
||
CoHasReturned | Coroutine* | bool | Returns true if the given Coroutine* has called CoReturn(..) Returns true if the given Coroutine* has executed a return; statement Returns false otherwise If CoHasReturned(..) returns true, you may call CoRun(..) on that coroutine. If CoHasReturned(..) returns false, you may not call CoRun(..) on that coroutine and you should call CoEnd(..) | |
CoEnd | Coroutine* | Finalizes and de-allocates a coroutine that has returned. | ||
CoKill | Coroutine* | Same as CoEnd, but also works if the Coroutine* has not returned yet. This is useful if: - You don't need any more output from the coroutine, but the coroutine has not returned. - Your coroutine is in an infinite loop. CoKill should not be used if your coroutine still owns allocated memory, other coroutines or other resources. |
Main stack:
____________________
| saved | <----\
| r4-r12, lr, pc | |
|------------------| |
| coroutine caller | | Coroutine object:
| local variables | | ____________________
| Coroutine* gen; | ------|---> | coroutine SP | -----\
| | | |------------------| |
| | \ -----| caller SP | |
|------------------| |
| unused | |
| coroutine | |
| stack space | |
|------------------| |
| saved | <---/
| r4-r12, lr pc |
|------------------|
| coroutine local |
| variables |
|__________________|