Home

Awesome

llco

A low-level coroutine library for C.

The main purpose of this project is to power sco and neco, which are more general purpose coroutine libraries.

Features

Example


void cleanup(void *stack, size_t stack_size, void *udata) {
    // Free the coroutine stack
    free(stack);
}

void entry(void *udata) {
    printf("Coroutine started\n");
    // Switch back to the main thread and cleanup this coroutine
    llco_switch(0, true);
}

int main(void) {
    // Start a coroutine from the main function using an newly allocated stack.
    struct llco_desc desc = {
        .stack = malloc(LLCO_MINSTACKSIZE),
        .stack_size = LLCO_MINSTACKSIZE,
        .entry = entry,
        .cleanup = cleanup,
    };
    llco_start(&desc, false);
    printf("Back to main\n");
}

API

// Switch to another coroutine. Set the `co` param to NULL to switch to the 
// main function. Use the final param to tell the program that you are done
// with the current coroutine, at which point it's respective `cleanup` 
// callback will be called.
void llco_switch(struct llco *co, bool final);

// Start a new coroutine. This can be called from the main function or a 
// nested coroutine.
void llco_start(struct llco_desc *desc, bool final);


// Return the current coroutine or NULL if not currently running in a
// coroutine.
struct llco *llco_current(void);

// Returns a string that indicates which coroutine method is being used by
// the program. Such as "asm" or "ucontext", etc.
const char *llco_method(void *caps);

Caveats

Compiler Options

Running test

# Basic test
cc llco.c test.c && ./a.out

# Using Valgrind
cc -DLLCO_VALGRIND llco.c test.c && valgrind ./a.out

# Using Emscripten (Web Assembly)
emcc -sASYNCIFY llco.c test.c && node ./a.out.js

Acknowledgements

Much of the assembly code was adapted from the minicoro project by Eduardo Bart, which was originally adapted from the Lua Coco project by Mike Pall.

License

Public Domain or MIT No Attribution, your choice.