Serene Runtime 1.0.0
C runtime for the Serene programming language
Loading...
Searching...
No Matches
fiber.h
Go to the documentation of this file.
1/* -*- C -*-
2 * Serene programming language
3 * Copyright (C) 2019-2026 Sameer Rahmani <[email protected]>
4 *
5 * This library is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19/** @file
20 AI Generated (🤦)
21 Fiber subsystem overview
22
23 Stackful, cooperative fibers for the runtime. A fiber is a function plus its
24 own stack, so it can pause at any call depth and resume later. Nothing is
25 preempted. A fiber runs until it explicitly yields, suspends, or finishes.
26
27 Terminology (used throughout the fiber subsystem)
28 fiber a unit of work with its own stack. It can pause and resume.
29 os thread a thread the operating system schedules.
30 worker the state one os thread uses to run fibers. It holds a local
31 queue of ready fibers and a worker's loop. There is one
32 worker per os thread.
33 worker's loop a special fiber that stands in for the os thread. A running
34 fiber switches back to it to hand control over, and it picks
35 the next fiber to run.
36 worker routine the steps an os thread repeats. It takes a fiber, switches
37 into it, deals with how the fiber gave up control, and parks
38 when no fiber is runnable.
39 scheduler there is exactly one. It owns the shared ready queue and the
40 list of live fibers and decides what runs next. It does not
41 run fibers itself, workers do.
42 suspend a fiber steps off every queue and waits to be woken. Its os
43 thread stays free to run other fibers.
44 park an os thread blocks because no fiber is runnable anywhere. A
45 notify wakes it.
46
47 Every fiber stack is the same fixed size (SRN_FIBER_DEFAULT_STACK_SIZE), one
48 mapping with a guard page that never grows. Uniform size is a deliberate
49 constraint, not an accident. It lets a finished fiber's stack be handed to any
50 later fiber (the stack ring TODO below) without tracking size classes, and it
51 keeps switch and mapping costs predictable.
52
53 Control flow is a hub. A fiber never jumps to another fiber. It switches back
54 to its worker's loop, which picks the next one.
55
56 scheduler ready queue: [F2] -> [F5] -> ...
57 | the os thread takes the head
58 v
59 +-----------> worker's loop --- switch ---> running fiber
60 | |
61 | yield (re-enqueue, run next) ----------------+
62 | suspend (off-queue until srn_fiber_ready) -----+
63 | finish (reap) --------------------------------+
64 +--------------------------------------------------+
65
66 A running fiber gives up control three ways:
67 - yield still runnable, so it moves to the back of the ready queue.
68 - suspend off every queue until some party calls srn_fiber_ready. The wake
69 seam used by peer fibers, locks, and a future IO reactor.
70 - finish its entry returns and the fiber is reaped.
71
72 The spec book's fibers chapter (docs/spec/fibers.typ) is the long-form
73 reference. Keep this overview in step with it.
74*/
75
76#pragma once
77
78#include <stddef.h>
79#include <stdint.h>
80
81// Sanitizer detection. AddressSanitizer and ThreadSanitizer each need a little
82// per-fiber bookkeeping (the guarded fields below and the switch path in
83// fiber.c), and a normal build carries none of it. Every translation unit in a
84// build compiles with the same `-fsanitize` flags, so the struct layout stays
85// consistent within that build.
86#if defined(__SANITIZE_ADDRESS__)
87# define SRN_ASAN 1
88#elif defined(__has_feature)
89# if __has_feature(address_sanitizer)
90# define SRN_ASAN 1
91# endif
92#endif
93#ifndef SRN_ASAN
94# define SRN_ASAN 0
95#endif
96
97#if defined(__SANITIZE_THREAD__)
98# define SRN_TSAN 1
99#elif defined(__has_feature)
100# if __has_feature(thread_sanitizer)
101# define SRN_TSAN 1
102# endif
103#endif
104#ifndef SRN_TSAN
105# define SRN_TSAN 0
106#endif
107
108typedef struct srn_engine_t srn_engine_t;
109typedef struct srn_context_t srn_context_t;
111typedef struct srn_scheduler_t srn_scheduler_t;
112
113// What a fiber's entry produces, type-erased. It is an alias for `void *`, so
114// the fiber subsystem carries no dependency on the value model. A caller that
115// runs fibers over Serene values casts to and from its own type at the
116// boundary.
117typedef void *srn_fiber_result_t;
118
119#define srn_fiber_get_scheduler_m(fiber) fiber->ctx->engine->scheduler
120
121// TODO(lxsameer): We need to have a ring with a certain size, which
122// would be like a storage for ready to use stacks. When we're done with a fiber
123// put its stack in the ring and prepare it for another upcoming fiber.
124// it might be even a good idea to allocate a few stacks in advance on start
125// up. This ring should be per thread I think.
126
127/// Default size of every fiber stack. All fiber stacks share one size (see the
128/// subsystem overview), so this is a process-wide value, not a per-fiber one:
129/// the default here, eventually overridable through a CLI argument.
130///
131/// A fiber stack is fixed and cannot grow (see the fibers chapter), so the size
132/// must hold realistic call chains yet stay cheap to reserve in bulk. 128 KiB
133/// strikes that balance: deep enough for the runtime's C and JIT frames, while
134/// lazy page commit means a shallow fiber faults in only the one or two pages
135/// it touches and leaves the rest a virtual reservation. For scale, an OS
136/// thread stack is far too large to spawn fibers by the thousand, and a few KiB
137/// would overflow on modest nesting.
138#define SRN_FIBER_DEFAULT_STACK_SIZE (128U * 1024U)
139
140// -----------------------------------------------------------------------------
141// Saved machine context
142// -----------------------------------------------------------------------------
143/// The saved context of a suspended fiber is a single word: its stack pointer
144/// at the moment it was switched away from. The callee-saved registers live on
145/// the fiber's own stack, pushed by srn_fiber_swap and popped when it is
146/// resumed.
150
151// -----------------------------------------------------------------------------
152// Stack
153// -----------------------------------------------------------------------------
154/// One stack per fiber, mapped with a guard page at the low end so an overflow
155/// faults deterministically instead of corrupting a neighbour.
156/// the layout is like:
157/////
158/// |... frames ...|... guard page ...|
159/// ^ start ^ limit ^ guard
160///
161/// It is a bit unintuitive to see the guard pointing at the end of the the
162/// region, but conventionally, the guard is an OS page and since the stack
163/// grows downward and allocations normally grow upward, guard is actually
164/// the address that OS (POSIX in this example) will return to us as the
165/// starting point of the memory region. Or to put it in different terms, we
166/// store the stack frames, starting from the end of the allocated memory for
167/// the region and move toward the start of the allocated memory.
168typedef struct srn_fiber_stack_t {
169 /// High end, stack pointer initialises to this address
170 void *start;
171 /// Low end of usable region
172 void *limit;
173 /// The protected page to detect stack overflows
174 void *guard;
176
177// -----------------------------------------------------------------------------
178// Lifecycle
179// -----------------------------------------------------------------------------
180typedef enum srn_fiber_state_e : uint8_t {
181 /// Created, stack mapped, never resumed
183 /// On the run queue, eligible to run
185 /// Currently executing
187 /// Parked off the run queue, awaits srn_fiber_ready
189 /// Entry returned. The result is final
192
193/// The function a fiber runs. Allocations made through `ctx` land in the
194/// context's block.
195/// TODO(lxsameer): The shape is generic until code generation produces
196/// fibers, at which point it adopts the Serene ABI.
197/// TODO(lxsameer): Should we support two types of entry functions? one
198/// for C calling convention and one for FastC?
200
201/// Suspend commit callback. The worker routine runs it on its own side once the
202/// fiber has switched out. It registers `self` with whatever will wake it and
203/// re-checks the awaited condition. It returns true to stay suspended, or false
204/// to resume `self` at once because the condition already holds. It must not
205/// switch fibers.
206typedef bool (*srn_fiber_park_fn)(srn_fiber_t *self, void *arg);
207
209 /// Saved stack pointer (see srn_fiber_ctx_t)
212 /// The lifecycle state. Atomic because a waker may run on a different os
213 /// thread than the worker running the fiber. `srn_fiber_ready` flips
214 /// `SUSPENDED` to `READY` with a CAS while the worker running the fiber reads
215 /// and writes the same field. Making it atomic keeps every access whole, so a
216 /// read can never see an inconsistent value.
220 void *arg;
221 /// Set when state reaches SRN_FIBER_DONE. Type-erased (see
222 /// srn_fiber_result_t), the caller interprets it.
224
225 /// While this fiber is suspending, the commit the worker routine runs once
226 /// the fiber is off the stack, to publish it to its waker (see
227 /// srn_fiber_suspend). Valid only across that one suspend hand-off.
229 void *park_arg;
230
231#if SRN_ASAN
232 /// AddressSanitizer bookkeeping across switches.
233 void *fake_stack;
234#endif
235
236#if SRN_TSAN
237 /// ThreadSanitizer fiber handle. TSan tracks each fiber as its own execution
238 /// context, so the switch path tells it which one is current. Created with
239 /// the fiber and destroyed when it is reaped.
240 void *tsan_fiber;
241#endif
242
243 /// Intrusive link threading this fiber onto one of the scheduler's
244 /// singly-linked lists (the ready run queue, or a wait queue) without a
245 /// separate node allocation: the next pointer lives in the fiber itself. A
246 /// fiber belongs to at most one such list at a time, so one link suffices.
248
249 /// Head of the list of fibers blocked in srn_fiber_wait_for on this fiber.
250 /// They are threaded through their own `link` (a waiter is suspended, so off
251 /// the ready queue, and its `link` is free). When this fiber reaches DONE the
252 /// worker routine wakes them all.
254
255 /// Registry links.
256 ///
257 /// The scheduler keeps every live fiber on one doubly linked list through
258 /// these pointers. It is different from `link`. `link` says where a fiber
259 /// sits in the run order, the registry says the fiber exists at all. A fiber
260 /// joins the list when it is created and leaves when it is reaped, in
261 /// whatever state it is in between -- including SUSPENDED, which sits on no
262 /// queue.
263 ///
264 /// This is how the scheduler accounts for, cleans up, and (later) cancels its
265 /// fibers. Doubly linked so reaping can unlink from the middle in O(1).
268
269 /// For debugging purposes
270 const char *name;
271};
272
273// -----------------------------------------------------------------------------
274// Scheduler
275// -----------------------------------------------------------------------------
276[[nodiscard]] [[gnu::nonnull(1)]] srn_scheduler_t *
278
279/// The one stop tear down of the fiber subsystem, should be called once
280/// `srn_sched_run` has returned. It joins the os threads, then releases the
281/// stack of every fiber still registered (any left unreaped, such as one
282/// suspended with no party to wake it, or one left queued when the run stopped
283/// early), and frees the scheduler's own resources. The fiber structs
284/// themselves live in context blocks and are reclaimed with those blocks, not
285/// here.
286///
287/// The scheduler is NOT usable after this. A later `srn_sched_run` panics, and
288/// a repeated `srn_sched_shutdown` is a no-op (so the engine can call it
289/// unconditionally even after a caller already did).
290///
291/// Must be called from outside the pool, never from an os thread that is
292/// running a worker nor from a fiber, and only after `srn_sched_run` has
293/// returned. Calling it on a live pool panics -- stop the pool with
294/// `srn_sched_stop`, let `srn_sched_run` return, then shut down.
295[[gnu::nonnull(1)]] void srn_sched_shutdown(srn_scheduler_t *sched);
296
297/// Run the scheduler with `nworkers` os threads draining it, returning once the
298/// pool goes quiescent (every os thread parked on an empty queue) or a stop is
299/// requested with `srn_sched_stop`. The calling os thread becomes worker 0, so
300/// it does not return until then. `nworkers` is clamped to at least 1; with 1
301/// it is the calling os thread alone, which keeps execution single-threaded and
302/// cooperatively ordered. The spawned os threads are not joined here --
303/// `srn_sched_shutdown` joins them as part of tearing the subsystem down.
304[[gnu::nonnull(1)]] void srn_sched_run(srn_scheduler_t *sched, int nworkers);
305
306/// Ask a running scheduler to stop. Each worker routine checks the request at
307/// the top of each turn and stops once the fiber it is running yields or
308/// finishes, so a slice in flight is never cut mid-execution. `srn_sched_run`
309/// then returns. Fibers left queued stay unrun and are reclaimed by
310/// `srn_sched_shutdown`. Does not wait. Safe to call from any os thread,
311/// including a signal-driven context or a fiber. A no-op if the scheduler is
312/// not running.
313[[gnu::nonnull(1)]] void srn_sched_stop(srn_scheduler_t *sched);
314
315/// Record a fiber in the scheduler's registry of live fibers, where it stays
316/// until it is reaped.
317[[gnu::nonnull(1, 2)]] void srn_sched_register(srn_scheduler_t *sched,
318 srn_fiber_t *fiber);
319
320/// Place a fiber on a scheduler's ready queue, making it eligible to run.
321[[gnu::nonnull(1, 2)]] void srn_sched_enqueue(srn_scheduler_t *sched,
322 srn_fiber_t *fiber);
323
324// -----------------------------------------------------------------------------
325// Fibers
326// -----------------------------------------------------------------------------
327/// Create a fiber that will run entry(ctx, arg). The fiber
328/// allocates into its block and never releases it. A `stack_size` of 0 selects
329/// SRN_FIBER_DEFAULT_STACK_SIZE.
330[[nodiscard]] [[gnu::nonnull(1, 2, 3)]] srn_fiber_t *
332 srn_fiber_entry_t entry, void *arg, size_t stack_size);
333
334/// Yield cooperatively: re-enqueue the running fiber and run the next ready
335/// one. Acts on the fiber currently running on this thread.
336void srn_fiber_yield(void);
337
338/// Park the running fiber until a party calls srn_fiber_ready. The fiber
339/// switches out first. Only then does the scheduler run `commit` (see
340/// srn_fiber_park_fn) to register it and confirm it should stay parked.
341/// Registering only after the park completes is what makes it race free -- a
342/// waker can never observe a half parked fiber. Acts on the fiber currently
343/// running on this thread.
344[[gnu::nonnull(1)]] void srn_fiber_suspend(srn_fiber_park_fn commit, void *arg);
345
346/// Mark a suspended fiber runnable again. This is the seam an IO reactor,
347/// timer, or peer fiber uses to wake a fiber when the event it awaited occurs.
348[[gnu::nonnull(1)]] void srn_fiber_ready(srn_fiber_t *fiber);
349
350/// Block the calling fiber until `target` finishes, then return its result.
351[[gnu::nonnull(1)]] srn_fiber_result_t srn_fiber_wait_for(srn_fiber_t *target);
352
353/// The fiber currently running on this os thread (the bootstrap fiber if none).
355
356/// The worker's loop of the worker running on the calling os thread. The fiber
357/// that resumes when the current fiber yields, suspends, or finishes, the
358/// resumer a fiber's launcher hands control back to. Each worker has its own,
359/// so this is valid only on an os thread that is currently running the worker
360/// routine.
361[[gnu::returns_nonnull]] srn_fiber_t *srn_fiber_worker_loop(void);
362
363// -----------------------------------------------------------------------------
364// Context switch
365// -----------------------------------------------------------------------------
366/// Save the current execution context into `from`, restore `to`, and resume on
367/// `to`'s stack. Returns, on `from`'s stack, when a fiber later switches back
368/// into `from`.
369[[gnu::nonnull(1, 2)]] void srn_fiber_swap(srn_fiber_ctx_t *from,
370 srn_fiber_ctx_t *to);
371
372/// Initialise a fresh fiber context so the first srn_fiber_swap into it begins
373/// executing fn(arg) on `stack`.
374///
375/// `fn` is the fiber's entry: a `void (*)(void *)` that runs on the new stack
376/// and receives `arg`. It must NEVER return -- there is no frame beneath it, so
377/// a return traps in the trampoline. Instead it transfers control away with
378/// srn_fiber_switch (to yield) or srn_fiber_switch_final (when finished), and
379/// as its first action it calls srn_fiber_on_entry(). Typical shape:
380///
381/// static void worker(void *arg) {
382/// srn_fiber_on_entry(&scheduler); // hand the switch to the
383/// sanitizer
384/// ... do the fiber's work using arg ...
385/// srn_fiber_switch_final(&scheduler); // finished, never returns
386/// }
387[[gnu::nonnull(1, 3)]] void srn_fiber_ctx_make(srn_fiber_ctx_t *fiber_ctx,
388 srn_fiber_stack_t stack,
389 void (*fn)(void *), void *arg);
390
391/// Switch from `from` to `to`, both live fibers, telling AddressSanitizer about
392/// the stack change. `from` resumes where it left off when something later
393/// switches back into it.
394[[gnu::nonnull(1, 2)]] void srn_fiber_switch(srn_fiber_t *from,
395 srn_fiber_t *to);
396
397/// Like srn_fiber_switch, but for a fiber that has finished and must not be
398/// resumed: control transfers to `to` and never comes back. The fiber's entry
399/// function therefore ends at this call -- any code after it is unreachable,
400/// which is why this is [[noreturn]]. Nothing is freed here. The spent fiber's
401/// stack is left frozen and reclaimed later by its owner (the scheduler reaps a
402/// finished fiber and frees its stack via srn_fiber_stack_free).
403[[noreturn]] [[gnu::nonnull(1)]] void srn_fiber_switch_final(srn_fiber_t *to);
404
405/// Call as the first action inside a fresh fiber's entry. `from` is the fiber
406/// that started this one (the scheduler, or the bootstrap thread fiber). It
407/// completes the switch for AddressSanitizer and, since `from`'s stack bounds
408/// only become discoverable here, records them into `from` so a later switch
409/// back is tracked. `from` may be null. A no-op when the sanitizer is not in
410/// use.
412
413/// Call when a finished fiber is reaped, after it has switched away for the
414/// last time. Releases the fiber's ThreadSanitizer handle. A no-op when the
415/// sanitizer is not in use.
416[[gnu::nonnull(1)]] void srn_fiber_on_reap(srn_fiber_t *fiber);
417
418/// Represent the calling OS thread as the running fiber ("#0"), so the
419/// scheduler or a test can switch away from it and back. The thread's stack
420/// bounds are not queried here (there is no portable way). Under the sanitizer
421/// they are recorded by the first fiber's srn_fiber_on_entry. The saved context
422/// is written by the first switch away.
423[[gnu::nonnull(1)]] void srn_fiber_init_thread(srn_fiber_t *f);
424
425// -----------------------------------------------------------------------------
426// Stack provider (rt/fiber/stack_*.c)
427// -----------------------------------------------------------------------------
428/// Allocate a stack of at least `size` usable bytes plus a guard page, or
429/// SRN_FIBER_DEFAULT_STACK_SIZE when `size` is 0. Platform specific.
430[[nodiscard]] srn_fiber_stack_t srn_fiber_stack_alloc(size_t size);
431
433
434// -----------------------------------------------------------------------------
435// Helpers
436// -----------------------------------------------------------------------------
438 return (size_t)((char *)s.start - (char *)s.limit);
439}
void srn_sched_register(srn_scheduler_t *sched, srn_fiber_t *fiber)
Record a fiber in the scheduler's registry of live fibers, where it stays until it is reaped.
Definition scheduler.c:305
srn_fiber_t * srn_fiber_worker_loop(void)
The worker's loop of the worker running on the calling os thread.
Definition scheduler.c:934
void srn_fiber_switch_final(srn_fiber_t *to)
Like srn_fiber_switch, but for a fiber that has finished and must not be resumed: control transfers t...
Definition fiber.c:85
void srn_fiber_swap(srn_fiber_ctx_t *from, srn_fiber_ctx_t *to)
Save the current execution context into from, restore to, and resume on to's stack.
srn_fiber_t * srn_fiber_make(srn_context_t *ctx, srn_scheduler_t *sched, srn_fiber_entry_t entry, void *arg, size_t stack_size)
Create a fiber that will run entry(ctx, arg).
Definition fiber.c:169
void srn_fiber_ready(srn_fiber_t *fiber)
Mark a suspended fiber runnable again.
Definition scheduler.c:918
srn_fiber_result_t srn_fiber_wait_for(srn_fiber_t *target)
Block the calling fiber until target finishes, then return its result.
Definition scheduler.c:963
srn_fiber_stack_t srn_fiber_stack_alloc(size_t size)
Allocate a stack of at least size usable bytes plus a guard page, or SRN_FIBER_DEFAULT_STACK_SIZE whe...
Definition stack_posix.c:34
static size_t srn_fiber_stack_size(srn_fiber_stack_t s)
Definition fiber.h:437
void srn_fiber_ctx_make(srn_fiber_ctx_t *fiber_ctx, srn_fiber_stack_t stack, void(*fn)(void *), void *arg)
Initialise a fresh fiber context so the first srn_fiber_swap into it begins executing fn(arg) on stac...
Definition ctx_x86_64.c:29
void srn_fiber_init_thread(srn_fiber_t *f)
Represent the calling OS thread as the running fiber ("#0"), so the scheduler or a test can switch aw...
Definition fiber.c:137
void srn_sched_shutdown(srn_scheduler_t *sched)
The one stop tear down of the fiber subsystem, should be called once srn_sched_run has returned.
Definition scheduler.c:314
void srn_fiber_stack_free(srn_fiber_stack_t stack)
Definition stack_posix.c:67
void srn_sched_stop(srn_scheduler_t *sched)
Ask a running scheduler to stop.
Definition scheduler.c:849
void srn_sched_enqueue(srn_scheduler_t *sched, srn_fiber_t *fiber)
Place a fiber on a scheduler's ready queue, making it eligible to run.
Definition scheduler.c:593
srn_fiber_state_e
Definition fiber.h:180
@ SRN_FIBER_NEW
Created, stack mapped, never resumed.
Definition fiber.h:182
@ SRN_FIBER_RUNNING
Currently executing.
Definition fiber.h:186
@ SRN_FIBER_READY
On the run queue, eligible to run.
Definition fiber.h:184
@ SRN_FIBER_DONE
Entry returned. The result is final.
Definition fiber.h:190
@ SRN_FIBER_SUSPENDED
Parked off the run queue, awaits srn_fiber_ready.
Definition fiber.h:188
srn_fiber_result_t(* srn_fiber_entry_t)(srn_context_t *ctx, void *arg)
The function a fiber runs.
Definition fiber.h:199
srn_scheduler_t * srn_sched_init(srn_engine_t *engine)
Definition scheduler.c:246
srn_fiber_t * srn_fiber_current(void)
The fiber currently running on this os thread (the bootstrap fiber if none).
Definition scheduler.c:930
void srn_sched_run(srn_scheduler_t *sched, int nworkers)
Run the scheduler with nworkers os threads draining it, returning once the pool goes quiescent (every...
Definition scheduler.c:784
void srn_fiber_switch(srn_fiber_t *from, srn_fiber_t *to)
Switch from from to to, both live fibers, telling AddressSanitizer about the stack change.
Definition fiber.c:62
void srn_fiber_on_entry(srn_fiber_t *from)
Call as the first action inside a fresh fiber's entry.
Definition fiber.c:107
bool(* srn_fiber_park_fn)(srn_fiber_t *self, void *arg)
Suspend commit callback.
Definition fiber.h:206
void * srn_fiber_result_t
Definition fiber.h:117
enum srn_fiber_state_e srn_fiber_state_t
void srn_fiber_on_reap(srn_fiber_t *fiber)
Call when a finished fiber is reaped, after it has switched away for the last time.
Definition fiber.c:129
void srn_fiber_suspend(srn_fiber_park_fn commit, void *arg)
Park the running fiber until a party calls srn_fiber_ready.
Definition scheduler.c:898
void srn_fiber_yield(void)
Yield cooperatively: re-enqueue the running fiber and run the next ready one.
Definition scheduler.c:876
Engine is a structure to own the long living and main pieces of the compiler.
Definition engine.h:49
The saved context of a suspended fiber is a single word: its stack pointer at the moment it was switc...
Definition fiber.h:147
void * sp
Definition fiber.h:148
One stack per fiber, mapped with a guard page at the low end so an overflow faults deterministically ...
Definition fiber.h:168
void * guard
The protected page to detect stack overflows.
Definition fiber.h:174
void * limit
Low end of usable region.
Definition fiber.h:172
void * start
High end, stack pointer initialises to this address.
Definition fiber.h:170
srn_fiber_entry_t entry
Definition fiber.h:219
_Atomic srn_fiber_state_t state
The lifecycle state.
Definition fiber.h:217
srn_fiber_t * link
Intrusive link threading this fiber onto one of the scheduler's singly-linked lists (the ready run qu...
Definition fiber.h:247
srn_fiber_t * waiters
Head of the list of fibers blocked in srn_fiber_wait_for on this fiber.
Definition fiber.h:253
void * park_arg
Definition fiber.h:229
srn_fiber_result_t result
Set when state reaches SRN_FIBER_DONE.
Definition fiber.h:223
srn_fiber_park_fn park_commit
While this fiber is suspending, the commit the worker routine runs once the fiber is off the stack,...
Definition fiber.h:228
srn_context_t * ctx
Definition fiber.h:218
srn_fiber_stack_t stack
Definition fiber.h:211
srn_fiber_t * reg_prev
Registry links.
Definition fiber.h:266
void * arg
Definition fiber.h:220
const char * name
For debugging purposes.
Definition fiber.h:270
srn_fiber_t * reg_next
Definition fiber.h:267
srn_fiber_ctx_t fiber_ctx
Saved stack pointer (see srn_fiber_ctx_t)
Definition fiber.h:210