Skip to content

Minimal single-threaded async runtime in C built on stackful fibers with epoll/kqueue I/O and simple async APIs.

License

Notifications You must be signed in to change notification settings

joexbayer/async-fibers

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Async Fibers (C)

Minimal single-threaded async runtime built on stackful fibers.

Small but capable: spawn/await/cancel fibers, fiber-blocking I/O (epoll/kqueue), bounded channels, pooled fiber stacks, and a global or explicit runtime API with deterministic scheduling.

Idea

  • Fibers with explicit async_yield.
  • Fiber-blocking I/O via epoll/kqueue.
  • Global runtime by default; custom runtime optional.
  • No hidden allocations in hot paths (fiber stacks are pooled).

Platform support

  • macOS: arm64, x86_64 (kqueue)
  • Linux: x86_64 (epoll)

Quick start

#include "async.h"

static void worker(void *user)
{
    for (int i = 0; i <= 10; ++i) {
        printf("%d ", i);
        async_yield();
    }
}

int main(void)
{
    async_spawn(worker, NULL);
    async_spawn(worker, NULL);
    return async_run();
}

Core API

async_run();                  /* runs until idle */
async_spawn(worker, NULL);    /* Will use the global runtime */
async_spawn_with(&rt, worker, NULL); /* _with functions allow specifying a custom runtime */
async_await(handle);
async_yield();

I/O API

Simple IO API for basic operations, read, write, accept, etc.

async_io_t io = {0};
async_io_register(&io, fd);
async_read(&io, buf, len, &n);
async_write(&io, buf, len, &n);
async_accept_io(&io, &client);
async_io_close(&io);

See examples/ for usage.

I/O calls yield the current fiber until the fd is ready.

I/O examples

async_io_t must be zero-initialized before use:

async_io_t io = {0};
async_io_register(&io, fd);

Read once from a registered fd:

static void reader(void *user)
{
    async_io_t *io = (async_io_t *)user;
    char buf[128];
    size_t n = 0;

    if (async_read(io, buf, sizeof(buf), &n) != ASYNC_OK) {
        fprintf(stderr, "read failed\n");
    }
}

Write once to a registered fd:

static void writer(void *user)
{
    async_io_t *io = (async_io_t *)user;
    const char msg[] = "hello\n";
    size_t n = 0;

    if (async_write(io, msg, sizeof(msg) - 1, &n) != ASYNC_OK) {
        fprintf(stderr, "write failed\n");
    }
}

Channels

Bounded pointer channels for fiber-to-fiber messaging.

async_channel_t ch;
async_global_init(NULL);
async_channel_init(&ch, async_global(), 64, 64);
async_channel_send(&ch, payload);
async_channel_recv(&ch, &payload);
async_channel_close(&ch);
async_channel_shutdown(&ch);

Runtime setup

Create a custom runtime

Example in examples/custom_runtime.c.

Custom runtime example

async_config_t cfg = {0};
async_runtime_t rt;
if (async_runtime_init(&rt, &cfg) != ASYNC_OK) {
    return 1;
}

async_fiber_handle_t handle = async_spawn_with(&rt, worker, NULL);
if (handle.status != ASYNC_OK) {
    async_runtime_shutdown(&rt);
    return 1;
}

int result = async_runtime_run(&rt);
async_runtime_shutdown(&rt);
return result == ASYNC_OK ? 0 : 1;

Config defaults

  • task_capacity = 256
  • fiber_capacity = 64
  • fiber_stack_size = 64 * 1024
  • max_events = 64

Fiber stack guards and CPU state

  • Fiber stacks are guard-paged when allocated by the runtime pool. (User-provided stacks are not guarded.)
  • x87/MMX/SSE state is preserved across fiber swaps by default. (can be disabled with -DASYNC_FIBER_SAVE_X87=0.)
  • CET shadow stacks are supported ONLY on Linux x86_64 when enabled with -DASYNC_FIBER_SHADOW_STACK=1.

Build

make
make examples
make tests

Install

make install PREFIX=/usr/local
make uninstall PREFIX=/usr/local

Examples

Tests

  • To validate guard pages during tests, set ASYNC_TEST_GUARD_PAGES=1 (triggers an intentional SIGSEGV).

About

Minimal single-threaded async runtime in C built on stackful fibers with epoll/kqueue I/O and simple async APIs.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages