Serene Runtime 1.0.0
C runtime for the Serene programming language
Loading...
Searching...
No Matches
srn_scheduler_t Struct Reference
Collaboration diagram for srn_scheduler_t:
[legend]

Data Fields

srn_engine_tengine
 
srn_mutex_t lock
 Global lock.
 
srn_fiber_tready_head
 Global / overflow queue.
 
srn_fiber_tready_tail
 
srn_fiber_tregistry
 Registry: head of the doubly-linked list (through reg_prev/reg_next) of every live fiber, on a different axis from the run queues.
 
srn_cond_t work
 Worker coordination.
 
atomic_int idle
 
atomic_int runnable
 
int nworkers
 
_Atomic srn_sched_state_t state
 
srn_worker_tworkers
 srn_sched_run allocates these two arrays and srn_sched_shutdown frees them.
 
srn_thread_tos_threads
 
_Atomic bool run_active
 True for the duration of an srn_sched_run call.
 
bool destroyed
 Set once srn_sched_shutdown has torn the scheduler down.
 

Detailed Description

Definition at line 131 of file scheduler.c.

Field Documentation

◆ destroyed

bool srn_scheduler_t::destroyed

Set once srn_sched_shutdown has torn the scheduler down.

The scheduler is not usable afterwards, a further run panics, and a further shutdown is a no-op.

Definition at line 201 of file scheduler.c.

◆ engine

srn_engine_t* srn_scheduler_t::engine

Definition at line 132 of file scheduler.c.

◆ idle

atomic_int srn_scheduler_t::idle

Definition at line 175 of file scheduler.c.

◆ lock

srn_mutex_t srn_scheduler_t::lock

Global lock.

Guards the global/overflow queue, the registry, and the worker coordination fields below. It does NOT guard the per-worker local queues, which carry their own locks. Lock order is global-before-local: a worker may hold this while taking a local lock (only the park scan does), but a local lock is never held while taking this.

Definition at line 138 of file scheduler.c.

◆ nworkers

int srn_scheduler_t::nworkers

Definition at line 177 of file scheduler.c.

◆ os_threads

srn_thread_t* srn_scheduler_t::os_threads

Definition at line 192 of file scheduler.c.

◆ ready_head

srn_fiber_t* srn_scheduler_t::ready_head

Global / overflow queue.

Holds fibers enqueued with no current worker – an external waker, or the initial fibers made before the run. A worker drains its own local queue first, then this. FIFO through the intrusive link.

Definition at line 142 of file scheduler.c.

◆ ready_tail

srn_fiber_t* srn_scheduler_t::ready_tail

Definition at line 143 of file scheduler.c.

◆ registry

srn_fiber_t* srn_scheduler_t::registry

Registry: head of the doubly-linked list (through reg_prev/reg_next) of every live fiber, on a different axis from the run queues.

A fiber joins at srn_fiber_make and leaves when reaped, so the list is every fiber the scheduler is still responsible for, including SUSPENDED ones that sit on no run queue. It is how the scheduler accounts for and cleans them up.

Definition at line 149 of file scheduler.c.

◆ run_active

_Atomic bool srn_scheduler_t::run_active

True for the duration of an srn_sched_run call.

srn_sched_shutdown reads it to reject being called while a run is still in flight (it must run after run has returned). Atomic because shutdown may read it from a different thread than the one inside run.

Definition at line 197 of file scheduler.c.

◆ runnable

atomic_int srn_scheduler_t::runnable

Definition at line 176 of file scheduler.c.

◆ state

_Atomic srn_sched_state_t srn_scheduler_t::state

Definition at line 178 of file scheduler.c.

◆ work

srn_cond_t srn_scheduler_t::work

Worker coordination.

Parked os threads wait on work. idle counts parked os threads and runnable counts fibers waiting in ANY queue (local or global). Both are atomic because a push reads idle, and the park path reads runnable, without holding the lock the other side updates them under. The "idle++ then read runnable" park ordering against the "runnable++ then read idle" push ordering is what makes a lost wakeup impossible.

WARNING: that pairing is correct ONLY because all four of those operations are seq_cst (the default for atomic_fetch_add and atomic_load). announce_work does its runnable++ and its idle read with NO lock held, so the single seq_cst total order is the only thing tying it to the park path. Do NOT weaken these to acq_rel or relaxed for "speed". Weaken them and a push and a park can each fail to see the other, so an os thread sleeps on work forever while a runnable fiber sits in a queue. That is a lost wakeup, a hang. If these ever must be relaxed, the whole runnable/idle handshake has to move under the lock first, the way global_enqueue already does it, so the lock supplies the ordering the weaker atomics would not.

nworkers is fixed for a run. state drives termination. An os thread stops once it observes SRN_SCHED_STOPPING, set at quiescence (idle == nworkers and runnable == 0) or by srn_sched_stop.

Definition at line 174 of file scheduler.c.

◆ workers

srn_worker_t* srn_scheduler_t::workers

srn_sched_run allocates these two arrays and srn_sched_shutdown frees them.

They live until shutdown, so shutdown can join the threads and reap. The scheduler struct itself is immortal, but these arrays are not.

workers holds all nworkers workers in one array, so each worker can find the others to steal from. os_threads holds the OS threads the scheduler started. There is not one thread per worker. The caller's own thread runs worker 0, so the scheduler never starts a thread for it. Only workers 1 through nworkers-1 get a thread, so slot 0 of os_threads is unused and shutdown joins slots 1 through nworkers-1. A thread belongs here, not in srn_worker_t, because it marks a thread the scheduler started and must join, which is not the same as being a worker.

Definition at line 191 of file scheduler.c.


The documentation for this struct was generated from the following file: