xco
A minimal C11 concurrency library. No allocation, no atomics, no
hidden threads, no clocks. Single-threaded. Caller-provided storage.
An opt-in XCO_MT build extends it to N pinned threads (see below);
everything in the previous sentences stays true of the default build.
Layers
Bottom-up; each layer is a thin abstraction over the one below.
xco_mach — generic resumable function, a state machine. Step in a value, step out a value, report suspended/dead. Substrate shared by stack-switching coroutines and hand-coded state machines.
event substrate — pollable events (
xco_event_t) with a fused try-or-park primitive and a single-threaded FIFO ready queue. Concrete events: latch, countdown, notify, semaphore/mutex, select (any-of) and allof, queue (with chan = unbuffered queue), broadcast, cancel, timer + pluggable timer source, timeout, ticker.xco_task — lifecycle handle for a running step: a done latch (fires with the return value) plus a cancel latch.
xco_task_group_tfans these in/out across a dynamic set of tasks.xco_coro — stack-switching coroutines. Asymmetric:
xco_suspendalways returns to the most recent resumer. Embedsxco_mach_tas first member, so generic code overxco_mach_t *works on both coroutines and hand-coded state machines.xco_op — pure-effect IO layer. Coroutines submit ops onto the runtime; the host pulls a batch via
xco_rt_take_ops, executes them however it likes (io_uring, threads, mocks, replay), and feeds completions back viaxco_op_complete. The library makes no syscalls — that property extends to IO via this layer.xco_thread (XCO_MT, opt-in) — freestanding thread abstraction: a Vyukov MPSC inbox, a host wakeup fn pointer, and a park handshake. Waiters gain a home thread and
xco_waiter_firebecomes a routing seam: off-home, the waiter itself is posted as the message and fires on its home thread's drain. Threads without runtimes (workers) are first-class — their job queue is the inbox. Thread creation, blocking, and waking stay host bindings (condvar, eventfd,WFE); xco adds only<stdatomic.h>. Design and contracts:XCO_MT.md. Changes struct layouts, so a whole program must agree on the flag; the build producesbuild/libxco.aandbuild/mt/libxco_mt.a.
Properties
- No allocation. Every event, task, queue buffer, and coroutine stack is caller-provided.
- No atomics. Single-threaded by construction; the substrate is built around an O(1) intrusive ready queue and intrusive doubly-linked waitlists.
- No clocks. The host passes
nowintoxco_rt_run; timers are driven by a pluggable source (in-tree pairing heap). - One-waiter invariant. A suspended machine is parked on at most one
event. Multi-wait is composed in the event graph (build a
select, park on that).
Build
make # builds build/libxco.a
make test # builds and runs the test suite
The platform is auto-detected from uname -m; override with
PLATFORM=<dir> (must match a directory under platform/).
Layout
xco.h,xco.c— architecture-neutral library.platform/<arch>/xco_platform.{h,c}— register save/restore and initial-context setup. Adding an arch means adding a directory here.tests/test_xco.c— coroutine smoke test.tests/test_event.c— event substrate.tests/test_op.c— IO/op layer.