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.