|
Serene Runtime 1.0.0-dev
C runtime for the Serene programming language
|
This page is the implementation map for the fiber subsystem: the files, the objects, and how a fiber is created, switched, scheduled, and torn down. For the design and its rationale — why stackful, why fixed stacks with a guard page, why a reason-agnostic suspend/ready pair, why a work-stealing deque — see the "Fibers", chapter of the language report. The I/O reactor this subsystem waits on is documented in Reactor implementation overview.
| File | Role |
|---|---|
| serene/rt/fiber.h | Public surface: srn_fiber_t (fully public), the state enum, the scheduler/fiber verbs, and the context-switch declarations. |
| rt/fiber/fiber.c | Architecture-neutral fiber mechanics: srn_fiber_make, the launcher, the switch wrappers, srn_fiber_on_entry/on_reap, per-thread init. |
| rt/fiber/scheduler.c | The one scheduler and its workers: run queues (Chase–Lev deques + a shared global queue), srn_sched_run/stop/drain/shutdown, work-stealing, parking, and quiescence. |
| rt/fiber/arch/ctx_<cpu>.c, arch/switch_<cpu>.S, arch/stack_<cpu>.h | Per-architecture context fabrication and the srn_fiber_swap/srn_fiber_trampoline assembly. |
| rt/fiber/platform/stack_posix.c | The stack provider: mmap + guard page, behind srn_fiber_stack_alloc/free. |
| rt/fiber/platform/thread_posix.c, serene/rt/fiber/thread.h | The OS-thread shim (spawn/join, mutex, cond), modelled by intent, not a 1:1 pthread wrapper. |
| rt/fiber/io.c, serene/rt/fiber/io.h | The fiber↔reactor bridge and the fiber-facing IO surface — see below. |
A srn_fiber_t is a function plus its own stack. Its saved context is a single word — the stack pointer at the moment it switched away (srn_fiber_ctx_t); the callee-saved registers live on the fiber's own stack, pushed by srn_fiber_swap. A fiber moves through five states:
There is exactly one srn_scheduler_t; it owns the ready work and a registry of every live fiber. It has no event loop. srn_sched_run(sched, nworkers) turns the calling OS thread into worker 0, spawns the rest, and drains work until the pool goes quiescent or a stop is requested.
Terminology is precise throughout (see the report's glossary): a worker is the per-OS-thread state, the worker's loop stands in for the OS thread and picks the next fiber, fibers suspend while OS threads park.
io.c is the only layer that knows both fibers and the reactor. A blocking-looking call (srn_fiber_read, srn_fiber_accept, …) builds a request on the fiber's own stack and suspends; the submit happens inside the park-commit (reactor_submit_commit), so the fiber is fully parked before the completion can land. srn_reactor_consume, run by the owning worker, copies each completion into the on-stack waiter, readies the fiber, and drops the in-flight count. Each call returns a per-op fallible value (maybe_error null on success). The non-suspending helpers (socket, bind, open, …) share that convention but never touch the reactor. Regular-file reads and writes, which a readiness backend cannot poll, are served by a synchronous syscall on the worker (see Reactor implementation overview).
Every platform/architecture file carries a whole-file target-macro guard, so the whole source set compiles for a cross target and only the matching files emit symbols (see the report's portability milestone). The switch path is annotated for AddressSanitizer and ThreadSanitizer — srn_fiber_t gains a fake_stack field under ASan and a tsan_fiber handle under TSan, so a build's struct layout depends on its sanitizer flags, and a consumer must match them.