https://github.com/not-nik/coop
API and ABI independent, user-space multitasking
https://github.com/not-nik/coop
async coroutines multitasking multithreading x86-64
Last synced: about 1 month ago
JSON representation
API and ABI independent, user-space multitasking
- Host: GitHub
- URL: https://github.com/not-nik/coop
- Owner: Not-Nik
- License: mit
- Created: 2021-01-07T02:43:15.000Z (about 5 years ago)
- Default Branch: master
- Last Pushed: 2022-03-08T16:18:07.000Z (about 4 years ago)
- Last Synced: 2025-10-13T00:56:34.298Z (5 months ago)
- Topics: async, coroutines, multitasking, multithreading, x86-64
- Language: C
- Homepage: https://notnik.cc/posts/async/
- Size: 11.7 KB
- Stars: 3
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# coop
Coop is an experimental asynchronous multitasking scheduler that tries to
run everywhere. It has literally no run time dependencies except for a
proper x86_64/amd64 machine set to long mode. It's only build-time
dependency is a C compiler supporting GCC inline assembly. Technically,
coop should run, and work, on everything you can compile to, including
baremetal and even Windows.
Additionally, if you want to use coop while staying sane and stack
overflow-less you will need some memory allocation function like
`malloc()` and if you want to regain some of you precious memory
also one like `free()`.
## Usage example
```c
#include
#include
#include "lib/coop.h"
void my_async_func() {
puts("Func1: 1");
yield;
puts("Func1: 2");
dump;
}
void my_async_func2() {
puts("Func2: 1");
yield;
puts("Func2: 2");
dump;
}
int main() {
coop_context ctx = make_context();
task_t t1 = {0}, t2 = {0};
coop_stack s1 = {.size = 4096, .stack_bottom = malloc(4096)};
coop_stack s2 = {.size = 4096, .stack_bottom = malloc(4096)};
add_task(&ctx, &t1, s1, my_async_func);
add_task(&ctx, &t2, s2, my_async_func2);
start(&ctx);
free(s1.stack_bottom);
free(s2.stack_bottom);
return 0;
}
```
## Pitfalls
> Most importantly coop isn't tested further than what's in `test.c`
coop does have two more semi-runtime dependency. Your compiler has to push
it's rbp value to the stack. If it doesn't, you will get at least the last
variable created before yielding control, or, if you don't have a variable,
the return pointer, overwritten, both of which can cause very bad things to
happen.
Additionally, the ABI you are using can't consider RAX and RDX nonvolatile
(callee-saved), since coop a) uses these registers internally and therefore
b) doesn't save them. Luckily this is a) true for the two major ABI's and
b) nobody would create such an ABI because these registers are used by
both the `div` and `idiv` instruction.