logos.std.rt.fiber
Module std · package logos-std
Types
structChan
struct Chan
Bounded FIFO channel between fibers on one thread, backed by a ring buffer.
At most one suspended sender AND one suspended receiver at a time; violating
this invariant is a caller error (see chan_send / chan_recv).
Fields
buf: *mut u8
cap: i64
elem_size: i64
head: i64
len: i64
recv_fiber: i64
send_fiber: i64
send_val: i64
tail: i64
structFiber
struct Fiber
Represents one cooperative fiber: saved context, owned stack, FLS slots, and intrusive ready-queue link.
Fields
ctx: FiberCtx
fls: *mut i64
next: *mut Fiber
stack_base: *mut u8
stack_size: i64
structFiberCtx
struct FiberCtx
Holds the register state of a suspended fiber (callee-saved regs + rsp).
Maps 1:1 to the register save area in fiber_ctx.S; field order and sizes
MUST NOT change without updating the asm offsets.
Fields
r12: i64
r13: i64
r14: i64
r15: i64
rbp: i64
rbx: i64
rsp: i64
structFutureSlot
struct FutureSlot
Heap-allocated one-shot slot shared between a producer and its consumer.
Fields
value_ptr: *mut T
Pointer to the delivered value; null until future_complete fills it in.
waiter: i64
*mut Fiber of the suspended consumer as i64, or 0 if none is waiting.
waiter_thr: i64
*mut Thread of the waiting consumer as i64; 0 means same-thread.
structLatch
struct Latch
Count-down latch: a single waiter fiber suspends until the count reaches 0.
Single-thread only; supports at most one concurrent waiter.
Fields
count: i64
waiter: i64
structReactor
struct Reactor
Per-thread io_uring reactor: one ring plus a count of fibers parked on in-flight I/O.
Fields
parked_count: i64
ring: *mut u8
structScheduler
struct Scheduler
Owns one thread’s cooperative fiber state: intrusive ready FIFO, running fiber, deferred-free slot, and optional retired-stack pool.
Fields
current: i64
pending_free: i64
ready_head: *mut Fiber
ready_tail: *mut Fiber
sched_ctx: FiberCtx
stack_pool_buf: *mut i64
stack_pool_cap: i64
stack_pool_len: i64
structSpscRing
struct SpscRing
A bounded single-producer/single-consumer ring of (fn_ptr, arg) pairs.
One slot stays unused: a ring of capacity cap holds at most cap - 1 entries.
Fields
buf: *mut i64
cap: i64
head: i64
tail: i64
structThread
struct Thread
A worker thread: cooperative Scheduler, io_uring Reactor, SPSC inbox, wakeup eventfd.
Fields
idx: i32
inbox: *mut SpscRing
notify_fd: i32
pool: *mut ThreadPool
pthread_id: i64
reactor: *mut Reactor
sched: *mut Scheduler
sleeping: i64
structThreadPool
struct ThreadPool
A fixed set of worker Threads, each running its own per-thread reactor loop.
Fields
count: i32
shutdown: i64
threads: *mut i64
Functions
fnchan_free
fn chan_free(ch: *mut Chan<T>) -> void
Deallocates the channel, its ring buffer, and any pending suspended-send value.
fnchan_new
fn chan_new(cap: i64) -> *mut Chan<T>
Creates a heap-allocated channel holding up to cap items; free with chan_free.
fnchan_recv
fn chan_recv(ch: *mut Chan<T>) -> T
Receives a value from the channel; suspends the current fiber while the channel is empty.
Unblocks a suspended sender by moving its pending value into the ring. If another receiver is already suspended (caller error), the result is undefined (null read).
fnchan_send
fn chan_send(ch: *mut Chan<T>, val: T) -> void
Sends val into the channel; suspends the current fiber while the channel is full.
Wakes a suspended receiver if one is waiting. If another sender is already
suspended (caller error), returns immediately and val is silently dropped.
fncurrent_fiber
fn current_fiber() -> i64
Returns a pointer-sized identifier of the current fiber, or 0 if none.
The reactor stores this as io_uring SQE user_data to know which fiber to
re-enqueue on CQE delivery.
fnfiber_sleep_ms
fn fiber_sleep_ms(ms: i64) -> i32
Sleeps the current fiber for ms milliseconds.
Same return contract as fiber_sleep_ns; negative ms returns -22.
fnfiber_sleep_ns
fn fiber_sleep_ns(ns: i64) -> i32
Sleeps the current fiber for ns nanoseconds via IORING_OP_TIMEOUT.
Must run inside a fiber on a thread with a reactor installed.
Returns 0 on success (kernel -ETIME normalised); -22 for no reactor or
negative ns, -12 when the SQ is full.
fnfls_get
fn fls_get(key: i64) -> i64
Returns the current fiber’s FLS value for key, or 0 when no fiber is running.
key is not bounds-checked; valid range is 0..fls_slots().
fnfls_key_cqe_result
fn fls_key_cqe_result() -> i64
Returns the FLS key reserved for the fiber reactor’s CQE result (slot 0).
fnfls_set
fn fls_set(key: i64, val: i64) -> void
Sets the current fiber’s FLS value for key; no-op when no fiber is running.
key is not bounds-checked; valid range is 0..fls_slots().
fnfls_slots
fn fls_slots() -> i64
Returns the number of fiber-local storage slots per fiber.
fnfuture_complete
fn future_complete(slot: *mut FutureSlot<T>, val: T) -> void
Stores val into slot and wakes its waiting consumer, if any.
Wakes cross-thread via cross_thread_enqueue when the waiter lives on another thread.
fnfuture_get
fn future_get(slot: *mut FutureSlot<T>) -> T
Returns the value from slot, suspending the current fiber until it is ready.
Caller is responsible for freeing slot itself after future_get returns.
fnfuture_slot_new
fn future_slot_new() -> *mut FutureSlot<T>
Allocates a new FutureSlot<T>, shared between the producer and consumer.
fnlatch_count_down
fn latch_count_down(l: *mut Latch) -> void
Decrements the count (called by workers); wakes the waiter when the count reaches 0.
Extra calls after the count hits 0 are no-ops (no underflow).
fnlatch_free
fn latch_free(l: *mut Latch) -> void
Deallocates a Latch created by latch_new.
fnlatch_new
fn latch_new(count: i64) -> *mut Latch
Creates a heap-allocated Latch with the given initial count; free with latch_free.
fnlatch_wait
fn latch_wait(l: *mut Latch) -> void
Suspends the current fiber until the count reaches 0; returns immediately if already 0.
Single waiter only: a second concurrent latch_wait overwrites the first, deadlocking it.
fnlogos_fiber_done
fn logos_fiber_done() -> void
Terminates the current fiber: marks it for freeing and switches back to the
scheduler context; never returns.
Called by the logos_fiber_entry trampoline (fiber_ctx.S) after the fiber
function returns.
fnpark_fiber
fn park_fiber() -> void
Parks the current fiber: like yield_fiber() but WITHOUT re-enqueueing it.
The caller must arrange re-enqueueing later (e.g. unpark_fiber from a
reactor CQE handler). Returns when the fiber is resumed; no-op when no
fiber is running.
fnreactor_current
fn reactor_current() -> *mut Reactor
Returns the current thread’s reactor, or 0 if none is installed.
fnreactor_free
fn reactor_free(r: *mut Reactor) -> void
Tears down the reactor and frees its allocations; no-op on null r.
fnreactor_get_sqe
fn reactor_get_sqe(r: *mut Reactor) -> *mut u8
Obtains a free SQE from the reactor’s ring; returns 0 if the ring is full.
Caller must fill the SQE via a logos_io_uring_prep_* function before
reactor_submit_and_park.
fnreactor_has_parked
fn reactor_has_parked(r: *const Reactor) -> bool
Returns true if any fibers are parked awaiting CQEs; false for a null r.
fnreactor_new
fn reactor_new(entries: i32) -> *mut Reactor
Allocates and initialises a new reactor with entries SQ/CQ slots.
Returns 0 (null) on io_uring init failure.
fnreactor_poll
fn reactor_poll(r: *mut Reactor, blocking: bool) -> i32
Drains completions from the ring, re-enqueuing each CQE’s fiber with the result in its FLS[0].
If blocking, waits (unconditionally) for the first CQE, then drains the rest non-blocking.
Returns the number of CQEs processed, or a negative errno from the blocking wait.
fnreactor_run
fn reactor_run(s: *mut Scheduler, r: *mut Reactor) -> void
Drives scheduler s and reactor r until both the run queue and the parked set are empty.
Suits single-threaded tests and simple drivers without the full thread-pool machinery.
fnreactor_set_current
fn reactor_set_current(r: *mut Reactor) -> void
Installs r as the current thread’s reactor (asm TLS slot).
fnreactor_submit_and_park
fn reactor_submit_and_park(r: *mut Reactor, sqe: *mut u8) -> i32
Submits sqe with the current fiber attached as user_data, parking until its CQE arrives.
Returns the CQE result (stashed in FLS slot 0 by reactor_poll) on resume;
-22 (EINVAL) when not running inside a fiber; negative submit errors pass through.
fnsched_free
fn sched_free(s: *mut Scheduler) -> void
Frees the scheduler, munmapping any pooled stacks (does NOT free live fibers).
fnsched_new
fn sched_new() -> *mut Scheduler
Allocates and initialises a new scheduler.
The caller owns it and must call sched_free() when done.
fnsched_run
fn sched_run(s: *mut Scheduler) -> void
Runs the scheduler loop until the ready queue is empty.
Sets the per-thread scheduler pointer so spawn() and yield_fiber() work.
fnsched_set_current
fn sched_set_current(s: *mut Scheduler) -> void
Registers this scheduler as the current one for this thread.
Must be called before spawn() or yield_fiber() (sched_run sets it itself).
fnsched_set_stack_pool_cap
fn sched_set_stack_pool_cap(s: *mut Scheduler, cap: i64) -> void
Enables (or resizes) the retired-stack pool; cap = 0 disables pooling.
Call after sched_new() and before the first spawn(). Existing pool
contents are munmap’d before the slot buffer is replaced.
fnspawn
fn spawn(f: fn(i64) -> void, arg: i64) -> void
Spawns a fiber that will call f(arg) on its own stack and enqueues it as ready.
The current scheduler must have been set (sched_set_current or sched_run).
fnthread_pool_free
fn thread_pool_free(pool: *mut ThreadPool) -> void
Frees all per-thread resources (inbox, scheduler, reactor, eventfd) and the pool itself.
Call only after thread_pool_join.
fnthread_pool_join
fn thread_pool_join(pool: *mut ThreadPool) -> void
Blocks until every worker’s OS thread exits (pthread_join on each).
fnthread_pool_new
fn thread_pool_new(n: i32) -> *mut ThreadPool
Creates a pool of n workers, each with a scheduler, bounded SPSC inbox, eventfd,
and io_uring reactor. No OS threads run until thread_pool_start.
fnthread_pool_set_stack_pool_cap
fn thread_pool_set_stack_pool_cap(pool: *mut ThreadPool, cap: i64) -> void
Configures the per-fiber stack-pool capacity on every worker’s scheduler.
Must be called BEFORE thread_pool_start — once a worker thread is running,
its scheduler is accessed concurrently and touching it from outside is a data race.
fnthread_pool_signal_done
fn thread_pool_signal_done(pool: *mut ThreadPool) -> void
Sets the shutdown flag and wakes every worker; each exits once its scheduler, inbox, and parked I/O are all drained.
fnthread_pool_start
fn thread_pool_start(pool: *mut ThreadPool) -> void
Spawns one OS thread per worker; each runs its reactor loop until shutdown.
fnthread_submit
fn thread_submit(pool: *mut ThreadPool, target_idx: i32, f: fn(i64) -> void, arg: i64) -> void
Submits f(arg) to run as a new fiber on worker target_idx, waking it if asleep.
Spins while the target inbox is full. Assumes a single producer per inbox.
fnunpark_fiber
fn unpark_fiber(fiber_ptr: i64) -> void
Re-enqueues a previously-parked fiber into the ready queue. Called by the reactor when a CQE for a parked fiber arrives; no-op when no scheduler is set.
fnyield_fiber
fn yield_fiber() -> void
Yields voluntarily: re-enqueues the current fiber and switches to the scheduler. Returns when the scheduler picks this fiber again.