Serene Runtime 1.0.0-dev
C runtime for the Serene programming language
Loading...
Searching...
No Matches
fiber_tests.h File Reference
#include <stdatomic.h>
#include <stdint.h>
#include <string.h>
#include "base.h"
#include "serene/rt/fiber.h"
#include "serene/rt/fiber/thread.h"
#include "serene/rt/mm/interface.h"
Include dependency graph for fiber_tests.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  spawn_copy_args_t
struct  fiber_mbox_t

Macros

#define FIBER_TESTS(X)

Functions

static void test_fiber_thread_stack_bounds ()
static srn_fiber_result_t auto_name_entry (srn_context_t *ctx, void *arg)
static srn_fiber_result_t auto_name_parent_entry (srn_context_t *ctx, void *arg)
static void test_fiber_auto_name ()
static void test_fiber_make_schedule ()
static srn_fiber_result_t spawn_copy_entry (srn_context_t *ctx, void *arg)
static void test_fiber_spawn_copy ()
static srn_fiber_result_t auto_workers_entry (srn_context_t *ctx, void *arg)
static void test_fiber_sched_auto_workers ()
static void test_fiber_types ()
static void test_fiber_stack ()
static void fiber_pp_entry (void *arg)
static void test_fiber_switch ()
static srn_fiber_result_t fiber_run_entry (srn_context_t *ctx, void *arg)
static void test_fiber_sched_run ()
static srn_fiber_result_t fiber_yield_entry (srn_context_t *ctx, void *arg)
static void test_fiber_sched_yield ()
static srn_fiber_result_t fiber_rr_entry (srn_context_t *ctx, void *arg)
static void test_fiber_sched_yield_round_robin ()
static bool fiber_mbox_park (srn_fiber_t *self, void *arg)
static srn_fiber_result_t fiber_consumer_entry (srn_context_t *ctx, void *arg)
static srn_fiber_result_t fiber_producer_entry (srn_context_t *ctx, void *arg)
static void test_fiber_sched_suspend ()
static void test_fiber_sched_park_abort ()
static bool fiber_stuck_park (srn_fiber_t *self, void *arg)
static srn_fiber_result_t fiber_stuck_entry (srn_context_t *ctx, void *arg)
static void test_fiber_sched_registry ()
static bool fiber_dwake_park (srn_fiber_t *self, void *arg)
static srn_fiber_result_t fiber_dwake_consumer_entry (srn_context_t *ctx, void *arg)
static srn_fiber_result_t fiber_dwake_producer_entry (srn_context_t *ctx, void *arg)
static void test_fiber_sched_double_wake ()
static srn_fiber_result_t fiber_wf_target_entry (srn_context_t *ctx, void *arg)
static srn_fiber_result_t fiber_wf_waiter_entry (srn_context_t *ctx, void *arg)
static void test_fiber_sched_wait_for ()
static void test_fiber_sched_wait_for_done ()
static srn_fiber_result_t fiber_wf_counting_waiter (srn_context_t *ctx, void *arg)
static void test_fiber_sched_wait_for_many ()
static srn_fiber_result_t fiber_mt_entry (srn_context_t *ctx, void *arg)
static void test_fiber_sched_mt_run ()
static srn_fiber_result_t fiber_mt_yield_entry (srn_context_t *ctx, void *arg)
static void test_fiber_sched_mt_yield ()
static srn_fiber_result_t fiber_stopper_entry (srn_context_t *ctx, void *arg)
static srn_fiber_result_t fiber_pending_entry (srn_context_t *ctx, void *arg)
static void test_fiber_sched_stop ()

Variables

static srn_fiber_tauto_name_child
static int spawn_copy_seen
static atomic_int auto_workers_ran
static srn_fiber_t fiber_pp_thread
static srn_fiber_t fiber_pp_worker
static int fiber_pp_ticks
static int fiber_pp_rounds
static int fiber_ok_value
static int fiber_run_counter
static int fiber_yield_log [4]
static int fiber_yield_n
static int fiber_rr_log [6]
static int fiber_rr_n
static fiber_mbox_t fiber_mbox
static int fiber_mbox_got
static srn_fiber_tfiber_dwake_waiter
static bool fiber_dwake_signalled
static int fiber_dwake_runs
static int fiber_wf_result
static srn_fiber_tfiber_wf_target
static srn_fiber_result_t fiber_wf_seen
static int fiber_wf_woke
static atomic_int fiber_mt_counter
static atomic_int fiber_mt_yield_counter
static atomic_int fiber_stop_rounds

Macro Definition Documentation

◆ FIBER_TESTS

#define FIBER_TESTS ( X)
Value:
X("fiber::types", test_fiber_types), X("fiber::switch", test_fiber_switch), \
X("fiber::stack", test_fiber_stack), \
X("fiber::thread_stack_bounds", test_fiber_thread_stack_bounds), \
X("fiber::auto_name", test_fiber_auto_name), \
X("fiber::make_schedule", test_fiber_make_schedule), \
X("fiber::sched::auto_workers", test_fiber_sched_auto_workers), \
X("fiber::spawn_copy", test_fiber_spawn_copy), X("fiber::sched::run", test_fiber_sched_run), \
X("fiber::sched::yield", test_fiber_sched_yield), \
X("fiber::sched::yield_round_robin", test_fiber_sched_yield_round_robin), \
X("fiber::sched::suspend", test_fiber_sched_suspend), \
X("fiber::sched::park_abort", test_fiber_sched_park_abort), \
X("fiber::sched::registry", test_fiber_sched_registry), \
X("fiber::sched::double_wake", test_fiber_sched_double_wake), \
X("fiber::sched::wait_for", test_fiber_sched_wait_for), \
X("fiber::sched::wait_for_done", test_fiber_sched_wait_for_done), \
X("fiber::sched::wait_for_many", test_fiber_sched_wait_for_many), \
X("fiber::sched::mt_run", test_fiber_sched_mt_run), \
X("fiber::sched::mt_yield", test_fiber_sched_mt_yield), \
X("fiber::sched::stop", test_fiber_sched_stop)
static void test_fiber_sched_registry()
static void test_fiber_sched_wait_for_many()
static void test_fiber_switch()
static void test_fiber_sched_double_wake()
static void test_fiber_make_schedule()
static void test_fiber_sched_mt_yield()
static void test_fiber_sched_auto_workers()
static void test_fiber_stack()
static void test_fiber_thread_stack_bounds()
Definition fiber_tests.h:56
static void test_fiber_types()
static void test_fiber_spawn_copy()
static void test_fiber_sched_mt_run()
static void test_fiber_sched_yield_round_robin()
static void test_fiber_sched_suspend()
static void test_fiber_sched_park_abort()
static void test_fiber_auto_name()
Definition fiber_tests.h:90
static void test_fiber_sched_yield()
static void test_fiber_sched_wait_for()
static void test_fiber_sched_run()
static void test_fiber_sched_stop()
static void test_fiber_sched_wait_for_done()

Definition at line 30 of file fiber_tests.h.

30#define FIBER_TESTS(X) \
31 X("fiber::types", test_fiber_types), X("fiber::switch", test_fiber_switch), \
32 X("fiber::stack", test_fiber_stack), \
33 X("fiber::thread_stack_bounds", test_fiber_thread_stack_bounds), \
34 X("fiber::auto_name", test_fiber_auto_name), \
35 X("fiber::make_schedule", test_fiber_make_schedule), \
36 X("fiber::sched::auto_workers", test_fiber_sched_auto_workers), \
37 X("fiber::spawn_copy", test_fiber_spawn_copy), X("fiber::sched::run", test_fiber_sched_run), \
38 X("fiber::sched::yield", test_fiber_sched_yield), \
39 X("fiber::sched::yield_round_robin", test_fiber_sched_yield_round_robin), \
40 X("fiber::sched::suspend", test_fiber_sched_suspend), \
41 X("fiber::sched::park_abort", test_fiber_sched_park_abort), \
42 X("fiber::sched::registry", test_fiber_sched_registry), \
43 X("fiber::sched::double_wake", test_fiber_sched_double_wake), \
44 X("fiber::sched::wait_for", test_fiber_sched_wait_for), \
45 X("fiber::sched::wait_for_done", test_fiber_sched_wait_for_done), \
46 X("fiber::sched::wait_for_many", test_fiber_sched_wait_for_many), \
47 X("fiber::sched::mt_run", test_fiber_sched_mt_run), \
48 X("fiber::sched::mt_yield", test_fiber_sched_mt_yield), \
49 X("fiber::sched::stop", test_fiber_sched_stop)

Function Documentation

◆ auto_name_entry()

srn_fiber_result_t auto_name_entry ( srn_context_t * ctx,
void * arg )
static

Definition at line 72 of file fiber_tests.h.

72 {
73 UNUSED(ctx);
74 UNUSED(arg);
75 return nullptr;
76}
#define UNUSED(x)
Definition utils.h:45
Here is the caller graph for this function:

◆ auto_name_parent_entry()

srn_fiber_result_t auto_name_parent_entry ( srn_context_t * ctx,
void * arg )
static

Definition at line 80 of file fiber_tests.h.

80 {
81 UNUSED(arg);
83 return nullptr;
84}
srn_fiber_t * srn_fiber_spawn(srn_context_t *ctx, srn_fiber_entry_t entry, void *arg)
Make and schedule a fiber with every default, the engine's scheduler, the configured stack size,...
Definition fiber.c:245
static srn_fiber_t * auto_name_child
Definition fiber_tests.h:78
static srn_fiber_result_t auto_name_entry(srn_context_t *ctx, void *arg)
Definition fiber_tests.h:72
Here is the call graph for this function:
Here is the caller graph for this function:

◆ auto_workers_entry()

srn_fiber_result_t auto_workers_entry ( srn_context_t * ctx,
void * arg )
static

Definition at line 180 of file fiber_tests.h.

180 {
181 UNUSED(ctx);
182 UNUSED(arg);
183 atomic_fetch_add(&auto_workers_ran, 1);
184 return nullptr;
185}
static atomic_int auto_workers_ran
Here is the caller graph for this function:

◆ fiber_consumer_entry()

srn_fiber_result_t fiber_consumer_entry ( srn_context_t * ctx,
void * arg )
static

Definition at line 448 of file fiber_tests.h.

448 {
449 UNUSED(ctx);
450 UNUSED(arg);
453 return &fiber_ok_value;
454}
static bool fiber_mbox_park(srn_fiber_t *self, void *arg)
static int fiber_ok_value
static int fiber_mbox_got
static fiber_mbox_t fiber_mbox
void srn_fiber_suspend(srn_fiber_park_fn commit, void *arg)
A suspended fiber is on no scheduler queue, and the scheduler does not track what it waits on – whoev...
Definition scheduler.c:1063
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fiber_dwake_consumer_entry()

srn_fiber_result_t fiber_dwake_consumer_entry ( srn_context_t * ctx,
void * arg )
static

Definition at line 571 of file fiber_tests.h.

571 {
572 UNUSED(ctx);
573 UNUSED(arg);
576 return &fiber_ok_value;
577}
static int fiber_dwake_runs
static bool fiber_dwake_park(srn_fiber_t *self, void *arg)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fiber_dwake_park()

bool fiber_dwake_park ( srn_fiber_t * self,
void * arg )
static

Definition at line 562 of file fiber_tests.h.

562 {
563 UNUSED(arg);
565 return false;
566 }
567 fiber_dwake_waiter = self;
568 return true;
569}
static srn_fiber_t * fiber_dwake_waiter
static bool fiber_dwake_signalled
Here is the caller graph for this function:

◆ fiber_dwake_producer_entry()

srn_fiber_result_t fiber_dwake_producer_entry ( srn_context_t * ctx,
void * arg )
static

Definition at line 579 of file fiber_tests.h.

579 {
580 UNUSED(ctx);
581 UNUSED(arg);
583 if (fiber_dwake_waiter != nullptr) {
585 fiber_dwake_waiter = nullptr;
586 srn_fiber_ready(w); // first waker: SUSPENDED -> READY, enqueued
587 srn_fiber_ready(w); // second waker: already READY -> no-op
588 }
589 return &fiber_ok_value;
590}
void srn_fiber_ready(srn_fiber_t *fiber)
Mark a suspended fiber runnable again, waking it when the event it awaited occurs.
Definition scheduler.c:1083
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fiber_mbox_park()

bool fiber_mbox_park ( srn_fiber_t * self,
void * arg )
static

Definition at line 439 of file fiber_tests.h.

439 {
440 fiber_mbox_t *mb = arg;
441 if (mb->has_value) {
442 return false;
443 }
444 mb->waiter = self;
445 return true;
446}
srn_fiber_t * waiter
Here is the caller graph for this function:

◆ fiber_mt_entry()

srn_fiber_result_t fiber_mt_entry ( srn_context_t * ctx,
void * arg )
static

Definition at line 715 of file fiber_tests.h.

715 {
716 UNUSED(ctx);
717 UNUSED(arg);
718 atomic_fetch_add(&fiber_mt_counter, 1);
719 return &fiber_ok_value;
720}
static atomic_int fiber_mt_counter
Here is the caller graph for this function:

◆ fiber_mt_yield_entry()

srn_fiber_result_t fiber_mt_yield_entry ( srn_context_t * ctx,
void * arg )
static

Definition at line 748 of file fiber_tests.h.

748 {
749 UNUSED(ctx);
750 int rounds = (int)(intptr_t)arg;
751 for (int i = 0; i < rounds; i++) {
752 atomic_fetch_add(&fiber_mt_yield_counter, 1);
754 }
755 return &fiber_ok_value;
756}
static atomic_int fiber_mt_yield_counter
void srn_fiber_yield(void)
Yield cooperatively, re-enqueue the running fiber and run the next ready one.
Definition scheduler.c:1039
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fiber_pending_entry()

srn_fiber_result_t fiber_pending_entry ( srn_context_t * ctx,
void * arg )
static

Definition at line 798 of file fiber_tests.h.

798 {
799 UNUSED(ctx);
800 UNUSED(arg);
801 // Never reached, the stopper ends the run first. It adds a large amount, so
802 // any accidental execution is visible in the count.
803 atomic_fetch_add(&fiber_stop_rounds, 1000);
804 return &fiber_ok_value;
805}
static atomic_int fiber_stop_rounds
Here is the caller graph for this function:

◆ fiber_pp_entry()

void fiber_pp_entry ( void * arg)
static

Definition at line 256 of file fiber_tests.h.

256 {
257 UNUSED(arg);
259 for (int i = 0; i < fiber_pp_rounds; i++) {
262 }
264}
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:87
void srn_fiber_switch(srn_fiber_t *from, srn_fiber_t *to)
Compiled without AddressSanitizer instrumentation, in stack-use-after-return mode ASan would place fr...
Definition fiber.c:65
void srn_fiber_on_entry(srn_fiber_t *from)
Call as the first action inside a fresh fiber's entry.
Definition fiber.c:110
static srn_fiber_t fiber_pp_thread
static int fiber_pp_rounds
static srn_fiber_t fiber_pp_worker
static int fiber_pp_ticks
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fiber_producer_entry()

srn_fiber_result_t fiber_producer_entry ( srn_context_t * ctx,
void * arg )
static

Definition at line 456 of file fiber_tests.h.

456 {
457 UNUSED(ctx);
458 UNUSED(arg);
459 fiber_mbox.value = 42;
460 fiber_mbox.has_value = true;
461 if (fiber_mbox.waiter != nullptr) {
462 srn_fiber_t *w = fiber_mbox.waiter;
463 fiber_mbox.waiter = nullptr;
465 }
466 return &fiber_ok_value;
467}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fiber_rr_entry()

srn_fiber_result_t fiber_rr_entry ( srn_context_t * ctx,
void * arg )
static

Definition at line 386 of file fiber_tests.h.

386 {
387 UNUSED(ctx);
388 int id = (int)(intptr_t)arg;
389 for (int i = 0; i < 3; i++) {
390 if (fiber_rr_n < 6) {
391 fiber_rr_log[fiber_rr_n++] = id;
392 }
394 }
395 return &fiber_ok_value;
396}
static int fiber_rr_n
static int fiber_rr_log[6]
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fiber_run_entry()

srn_fiber_result_t fiber_run_entry ( srn_context_t * ctx,
void * arg )
static

Definition at line 299 of file fiber_tests.h.

299 {
300 UNUSED(ctx);
301 UNUSED(arg);
303 return &fiber_ok_value;
304}
static int fiber_run_counter
Here is the caller graph for this function:

◆ fiber_stopper_entry()

srn_fiber_result_t fiber_stopper_entry ( srn_context_t * ctx,
void * arg )
static

Definition at line 786 of file fiber_tests.h.

786 {
787 UNUSED(ctx);
788 srn_scheduler_t *sched = arg;
789 // No yield in this loop, a yielded fiber goes to the back of the queue, so
790 // yielding would hand the pending fibers a turn before the stop lands.
791 for (int i = 0; i < 3; i++) {
792 atomic_fetch_add(&fiber_stop_rounds, 1);
793 }
794 srn_sched_stop(sched);
795 return &fiber_ok_value;
796}
void srn_sched_stop(srn_scheduler_t *sched)
Ask a running scheduler to stop.
Definition scheduler.c:978
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fiber_stuck_entry()

srn_fiber_result_t fiber_stuck_entry ( srn_context_t * ctx,
void * arg )
static

Definition at line 527 of file fiber_tests.h.

527 {
528 UNUSED(ctx);
529 UNUSED(arg);
530 srn_fiber_suspend(fiber_stuck_park, nullptr); // never readied
531 return &fiber_ok_value;
532}
static bool fiber_stuck_park(srn_fiber_t *self, void *arg)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fiber_stuck_park()

bool fiber_stuck_park ( srn_fiber_t * self,
void * arg )
static

Definition at line 521 of file fiber_tests.h.

521 {
522 UNUSED(self);
523 UNUSED(arg);
524 return true; // stay parked, with no waker
525}
Here is the caller graph for this function:

◆ fiber_wf_counting_waiter()

srn_fiber_result_t fiber_wf_counting_waiter ( srn_context_t * ctx,
void * arg )
static

Definition at line 678 of file fiber_tests.h.

678 {
679 UNUSED(ctx);
680 UNUSED(arg);
683 }
684 return &fiber_ok_value;
685}
static int fiber_wf_woke
static int fiber_wf_result
static srn_fiber_t * fiber_wf_target
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:1130
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fiber_wf_target_entry()

srn_fiber_result_t fiber_wf_target_entry ( srn_context_t * ctx,
void * arg )
static

Definition at line 621 of file fiber_tests.h.

621 {
622 UNUSED(ctx);
623 UNUSED(arg);
624 return &fiber_wf_result;
625}
Here is the caller graph for this function:

◆ fiber_wf_waiter_entry()

srn_fiber_result_t fiber_wf_waiter_entry ( srn_context_t * ctx,
void * arg )
static

Definition at line 627 of file fiber_tests.h.

627 {
628 UNUSED(ctx);
629 UNUSED(arg);
631 return &fiber_ok_value;
632}
static srn_fiber_result_t fiber_wf_seen
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fiber_yield_entry()

srn_fiber_result_t fiber_yield_entry ( srn_context_t * ctx,
void * arg )
static

Definition at line 341 of file fiber_tests.h.

341 {
342 UNUSED(ctx);
343 int id = (int)(intptr_t)arg;
344 for (int i = 0; i < 2; i++) {
347 }
348 return &fiber_ok_value;
349}
static int fiber_yield_n
static int fiber_yield_log[4]
Here is the call graph for this function:
Here is the caller graph for this function:

◆ spawn_copy_entry()

srn_fiber_result_t spawn_copy_entry ( srn_context_t * ctx,
void * arg )
static

Definition at line 151 of file fiber_tests.h.

151 {
152 UNUSED(ctx);
153 spawn_copy_seen = ((spawn_copy_args_t *)arg)->value;
154 return nullptr;
155}
static int spawn_copy_seen
Here is the caller graph for this function:

◆ test_fiber_auto_name()

void test_fiber_auto_name ( )
static

Definition at line 90 of file fiber_tests.h.

90 {
91 MAKE_ENGINE(mm, engine);
92 MAKE_CONTEXT(engine, ctx);
93 srn_scheduler_t *sched = engine->scheduler;
94
97 auto_name_child = nullptr;
98 (void)srn_fiber_spawn(ctx, auto_name_parent_entry, nullptr);
99
100 // Made off the pool, the creator tag is `m`.
101 TEST_CHECK(strncmp(a->name, "f#m:", 4) == 0);
102 TEST_CHECK(strncmp(b->name, "f#m:", 4) == 0);
103 TEST_CHECK(strcmp(a->name, b->name) != 0);
104
105 // Run the fibers so the registry is empty before the context goes away.
106 srn_sched_run(sched, 1);
107
108 // The child was made by the parent running on the single worker, id 0,
109 // and it is that worker's first spawn.
110 TEST_ASSERT(auto_name_child != nullptr);
111 TEST_CHECK(strcmp(auto_name_child->name, "f#0:1") == 0);
112
113 RELEASE_CONTEXT(ctx);
114 SHUTDOWN_ENGINE(mm, engine);
115}
#define TEST_CHECK(cond)
Definition acutest.h:95
#define TEST_ASSERT(cond)
Definition acutest.h:117
#define RELEASE_CONTEXT(x)
Definition base.h:46
#define SHUTDOWN_ENGINE(mm, engine)
Definition base.h:38
#define MAKE_ENGINE(mm, engine)
Definition base.h:32
#define MAKE_CONTEXT(engine, x)
Definition base.h:42
static srn_fiber_result_t auto_name_parent_entry(srn_context_t *ctx, void *arg)
Definition fiber_tests.h:80
void srn_sched_run(srn_scheduler_t *sched, size_t nworkers)
Run the scheduler with nworkers os threads draining it, returning once the pool goes quiescent (every...
Definition scheduler.c:875
char name[SRN_FIBER_NAME_MAX]
Debug name, the caller's choice copied at creation, or autogenerated when the caller passed none (see...
Definition fiber.h:333
Here is the call graph for this function:

◆ test_fiber_make_schedule()

void test_fiber_make_schedule ( )
static

Definition at line 120 of file fiber_tests.h.

120 {
121 MAKE_ENGINE(mm, engine);
122 MAKE_CONTEXT(engine, ctx);
123 srn_scheduler_t *sched = engine->scheduler;
124
125 srn_fiber_t *stay = srn_fiber_make(ctx, sched, "left-new", auto_name_entry, nullptr, 0);
126 srn_fiber_t *go = srn_fiber_make(ctx, sched, "scheduled", auto_name_entry, nullptr, 0);
127
129 TEST_CHECK(strcmp(go->name, "scheduled") == 0);
130 TEST_CHECK(strcmp(stay->name, "left-new") == 0);
131
133 srn_sched_run(sched, 1);
134
137
138 // Reap the never scheduled fiber while its struct (in the context block)
139 // is still alive, before releasing the context.
140 srn_sched_shutdown(sched);
141 RELEASE_CONTEXT(ctx);
142 SHUTDOWN_ENGINE(mm, engine);
143}
srn_fiber_t * srn_fiber_make(srn_context_t *ctx, srn_scheduler_t *sched, const char *name, srn_fiber_entry_t entry, void *arg, size_t stack_size)
Create a fiber that will run entry(ctx, arg), registered with sched but NOT scheduled.
Definition fiber.c:200
@ SRN_FIBER_NEW
Created, stack mapped, never resumed.
Definition fiber.h:236
@ SRN_FIBER_DONE
Entry returned. The result is final.
Definition fiber.h:244
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:333
void srn_fiber_schedule(srn_fiber_t *fiber)
Schedule a NEW fiber, making it eligible to run.
Definition scheduler.c:638
_Atomic srn_fiber_state_t state
The lifecycle state.
Definition fiber.h:277
Here is the call graph for this function:

◆ test_fiber_sched_auto_workers()

void test_fiber_sched_auto_workers ( )
static

Definition at line 190 of file fiber_tests.h.

190 {
192
193 MAKE_ENGINE(mm, engine);
194 MAKE_CONTEXT(engine, ctx);
195 srn_scheduler_t *sched = engine->scheduler;
196
197 atomic_store(&auto_workers_ran, 0);
198 for (int i = 0; i < 32; i++) {
199 (void)srn_fiber_spawn(ctx, auto_workers_entry, nullptr);
200 }
201
202 srn_sched_run(sched, 0);
203 TEST_CHECK(atomic_load(&auto_workers_ran) == 32);
204
205 RELEASE_CONTEXT(ctx);
206 SHUTDOWN_ENGINE(mm, engine);
207}
static srn_fiber_result_t auto_workers_entry(srn_context_t *ctx, void *arg)
size_t srn_thread_cpu_count(void)
The number of CPUs the calling process may run threads on, at least 1.
Here is the call graph for this function:

◆ test_fiber_sched_double_wake()

void test_fiber_sched_double_wake ( )
static

Definition at line 592 of file fiber_tests.h.

592 {
593 MAKE_ENGINE(mm, engine);
594 MAKE_CONTEXT(engine, ctx);
595 srn_scheduler_t *sched = engine->scheduler;
596 ASSERT_NOT_NULL(sched);
597
598 fiber_dwake_waiter = nullptr;
599 fiber_dwake_signalled = false;
601
602 // Consumer first, so it runs and suspends before the producer wakes it.
603 (void)srn_fiber_spawn(ctx, fiber_dwake_consumer_entry, nullptr);
604 (void)srn_fiber_spawn(ctx, fiber_dwake_producer_entry, nullptr);
605
606 srn_sched_run(sched, 1);
607
609
610 RELEASE_CONTEXT(ctx);
611 SHUTDOWN_ENGINE(mm, engine);
612}
#define ASSERT_NOT_NULL(x)
Definition base.h:30
static srn_fiber_result_t fiber_dwake_consumer_entry(srn_context_t *ctx, void *arg)
static srn_fiber_result_t fiber_dwake_producer_entry(srn_context_t *ctx, void *arg)
Here is the call graph for this function:

◆ test_fiber_sched_mt_run()

void test_fiber_sched_mt_run ( )
static

Definition at line 722 of file fiber_tests.h.

722 {
723 MAKE_ENGINE(mm, engine);
724 MAKE_CONTEXT(engine, ctx);
725 srn_scheduler_t *sched = engine->scheduler;
726 ASSERT_NOT_NULL(sched);
727
728 atomic_store(&fiber_mt_counter, 0);
729 enum { N = 256 };
730 for (int i = 0; i < N; i++) {
731 (void)srn_fiber_spawn(ctx, fiber_mt_entry, nullptr);
732 }
733
734 srn_sched_run(sched, 4);
735
736 TEST_CHECK(atomic_load(&fiber_mt_counter) == N);
737
738 RELEASE_CONTEXT(ctx);
739 SHUTDOWN_ENGINE(mm, engine);
740}
static srn_fiber_result_t fiber_mt_entry(srn_context_t *ctx, void *arg)
Here is the call graph for this function:

◆ test_fiber_sched_mt_yield()

void test_fiber_sched_mt_yield ( )
static

Definition at line 758 of file fiber_tests.h.

758 {
759 MAKE_ENGINE(mm, engine);
760 MAKE_CONTEXT(engine, ctx);
761 srn_scheduler_t *sched = engine->scheduler;
762 ASSERT_NOT_NULL(sched);
763
764 atomic_store(&fiber_mt_yield_counter, 0);
765 enum { N = 64, ROUNDS = 8 };
766 for (int i = 0; i < N; i++) {
767 (void)srn_fiber_spawn(ctx, fiber_mt_yield_entry, (void *)(intptr_t)ROUNDS);
768 }
769
770 srn_sched_run(sched, 4);
771
772 TEST_CHECK(atomic_load(&fiber_mt_yield_counter) == N * ROUNDS);
773
774 RELEASE_CONTEXT(ctx);
775 SHUTDOWN_ENGINE(mm, engine);
776}
#define ROUNDS
static srn_fiber_result_t fiber_mt_yield_entry(srn_context_t *ctx, void *arg)
Here is the call graph for this function:

◆ test_fiber_sched_park_abort()

void test_fiber_sched_park_abort ( )
static

Definition at line 494 of file fiber_tests.h.

494 {
495 MAKE_ENGINE(mm, engine);
496 MAKE_CONTEXT(engine, ctx);
497 srn_scheduler_t *sched = engine->scheduler;
498 ASSERT_NOT_NULL(sched);
499
501 fiber_mbox.value = 7;
502 fiber_mbox.has_value = true; // value present before the consumer runs
503 fiber_mbox_got = 0;
504
505 (void)srn_fiber_spawn(ctx, fiber_consumer_entry, nullptr);
506
507 srn_sched_run(sched, 1);
508
510 TEST_CHECK(fiber_mbox.waiter == nullptr); // never registered as a waiter
511
512 RELEASE_CONTEXT(ctx);
513 SHUTDOWN_ENGINE(mm, engine);
514}
static srn_fiber_result_t fiber_consumer_entry(srn_context_t *ctx, void *arg)
Here is the call graph for this function:

◆ test_fiber_sched_registry()

void test_fiber_sched_registry ( )
static

Definition at line 534 of file fiber_tests.h.

534 {
535 MAKE_ENGINE(mm, engine);
536 MAKE_CONTEXT(engine, ctx);
537 srn_scheduler_t *sched = engine->scheduler;
538 ASSERT_NOT_NULL(sched);
539
540 srn_fiber_t *stuck = srn_fiber_spawn(ctx, fiber_stuck_entry, nullptr);
541 ASSERT_NOT_NULL(stuck);
542
543 // Drains the ready queue. The stuck fiber suspends and is abandoned.
544 srn_sched_run(sched, 1);
546
547 // The registry lets shutdown find and free the abandoned fiber's stack.
548 srn_sched_shutdown(sched);
549
550 RELEASE_CONTEXT(ctx);
551 SHUTDOWN_ENGINE(mm, engine);
552}
@ SRN_FIBER_SUSPENDED
Parked off the run queue, awaits srn_fiber_ready.
Definition fiber.h:242
static srn_fiber_result_t fiber_stuck_entry(srn_context_t *ctx, void *arg)
Here is the call graph for this function:

◆ test_fiber_sched_run()

void test_fiber_sched_run ( )
static

Definition at line 306 of file fiber_tests.h.

306 {
307 MAKE_ENGINE(mm, engine);
308 MAKE_CONTEXT(engine, ctx);
309 srn_scheduler_t *sched = engine->scheduler;
310 ASSERT_NOT_NULL(sched);
311
313 enum { N = 4 };
314 srn_fiber_t *fibers[N];
315 for (int i = 0; i < N; i++) {
316 fibers[i] = srn_fiber_spawn(ctx, fiber_run_entry, nullptr);
317 ASSERT_NOT_NULL(fibers[i]);
318 }
319
320 srn_sched_run(sched, 1);
321
323 for (int i = 0; i < N; i++) {
324 // The struct lives in the context block after reaping. Only the stack is
325 // released, so state and result are still readable here.
326 TEST_CHECK(fibers[i]->state == SRN_FIBER_DONE);
327 TEST_CHECK(fibers[i]->result == &fiber_ok_value);
328 }
329
330 RELEASE_CONTEXT(ctx);
331 SHUTDOWN_ENGINE(mm, engine);
332}
static srn_fiber_result_t fiber_run_entry(srn_context_t *ctx, void *arg)
Here is the call graph for this function:

◆ test_fiber_sched_stop()

void test_fiber_sched_stop ( )
static

Definition at line 807 of file fiber_tests.h.

807 {
808 MAKE_ENGINE(mm, engine);
809 MAKE_CONTEXT(engine, ctx);
810 srn_scheduler_t *sched = engine->scheduler;
811 ASSERT_NOT_NULL(sched);
812
813 atomic_store(&fiber_stop_rounds, 0);
814 // Stopper first so it reaches the single worker before the pending fibers.
815 (void)srn_fiber_spawn(ctx, fiber_stopper_entry, sched);
816 enum { PENDING = 3 };
817 for (int i = 0; i < PENDING; i++) {
818 (void)srn_fiber_spawn(ctx, fiber_pending_entry, nullptr);
819 }
820
821 // Returns when the stopper calls srn_sched_stop, with the pending fibers
822 // still queued.
823 srn_sched_run(sched, 1);
824
825 // Only the stopper ran (three rounds); no pending fiber ran.
826 TEST_CHECK(atomic_load(&fiber_stop_rounds) == 3);
827
828 // Reap the pending fibers while their structs (in the context block) are
829 // still alive, before releasing the context. SHUTDOWN_ENGINE calls shutdown
830 // again, which is a no-op on an already torn-down scheduler.
831 srn_sched_shutdown(sched);
832
833 RELEASE_CONTEXT(ctx);
834 SHUTDOWN_ENGINE(mm, engine);
835}
static srn_fiber_result_t fiber_pending_entry(srn_context_t *ctx, void *arg)
static srn_fiber_result_t fiber_stopper_entry(srn_context_t *ctx, void *arg)
Here is the call graph for this function:

◆ test_fiber_sched_suspend()

void test_fiber_sched_suspend ( )
static

Definition at line 469 of file fiber_tests.h.

469 {
470 MAKE_ENGINE(mm, engine);
471 MAKE_CONTEXT(engine, ctx);
472 srn_scheduler_t *sched = engine->scheduler;
473 ASSERT_NOT_NULL(sched);
474
476 fiber_mbox_got = 0;
477
478 // Order matters, the consumer must be enqueued first so it runs and suspends
479 // before the producer fills the slot.
480 (void)srn_fiber_spawn(ctx, fiber_consumer_entry, nullptr);
481 (void)srn_fiber_spawn(ctx, fiber_producer_entry, nullptr);
482
483 srn_sched_run(sched, 1);
484
486
487 RELEASE_CONTEXT(ctx);
488 SHUTDOWN_ENGINE(mm, engine);
489}
static srn_fiber_result_t fiber_producer_entry(srn_context_t *ctx, void *arg)
Here is the call graph for this function:

◆ test_fiber_sched_wait_for()

void test_fiber_sched_wait_for ( )
static

Definition at line 634 of file fiber_tests.h.

634 {
635 MAKE_ENGINE(mm, engine);
636 MAKE_CONTEXT(engine, ctx);
637 srn_scheduler_t *sched = engine->scheduler;
638 ASSERT_NOT_NULL(sched);
639
640 fiber_wf_seen = nullptr;
641 // Waiter made first, so it runs and parks before the target finishes.
642 (void)srn_fiber_spawn(ctx, fiber_wf_waiter_entry, nullptr);
644
645 srn_sched_run(sched, 1);
646
648
649 RELEASE_CONTEXT(ctx);
650 SHUTDOWN_ENGINE(mm, engine);
651}
static srn_fiber_result_t fiber_wf_target_entry(srn_context_t *ctx, void *arg)
static srn_fiber_result_t fiber_wf_waiter_entry(srn_context_t *ctx, void *arg)
Here is the call graph for this function:

◆ test_fiber_sched_wait_for_done()

void test_fiber_sched_wait_for_done ( )
static

Definition at line 655 of file fiber_tests.h.

655 {
656 MAKE_ENGINE(mm, engine);
657 MAKE_CONTEXT(engine, ctx);
658 srn_scheduler_t *sched = engine->scheduler;
659 ASSERT_NOT_NULL(sched);
660
661 fiber_wf_seen = nullptr;
662 // Target made first, so it runs and finishes before the waiter runs.
664 (void)srn_fiber_spawn(ctx, fiber_wf_waiter_entry, nullptr);
665
666 srn_sched_run(sched, 1);
667
669
670 RELEASE_CONTEXT(ctx);
671 SHUTDOWN_ENGINE(mm, engine);
672}
Here is the call graph for this function:

◆ test_fiber_sched_wait_for_many()

void test_fiber_sched_wait_for_many ( )
static

Definition at line 687 of file fiber_tests.h.

687 {
688 MAKE_ENGINE(mm, engine);
689 MAKE_CONTEXT(engine, ctx);
690 srn_scheduler_t *sched = engine->scheduler;
691 ASSERT_NOT_NULL(sched);
692
693 fiber_wf_woke = 0;
694 // Three waiters made first so they all park, then the target finishes.
695 (void)srn_fiber_spawn(ctx, fiber_wf_counting_waiter, nullptr);
696 (void)srn_fiber_spawn(ctx, fiber_wf_counting_waiter, nullptr);
697 (void)srn_fiber_spawn(ctx, fiber_wf_counting_waiter, nullptr);
699
700 srn_sched_run(sched, 1);
701
703
704 RELEASE_CONTEXT(ctx);
705 SHUTDOWN_ENGINE(mm, engine);
706}
static srn_fiber_result_t fiber_wf_counting_waiter(srn_context_t *ctx, void *arg)
Here is the call graph for this function:

◆ test_fiber_sched_yield()

void test_fiber_sched_yield ( )
static

Definition at line 351 of file fiber_tests.h.

351 {
352 MAKE_ENGINE(mm, engine);
353 MAKE_CONTEXT(engine, ctx);
354 srn_scheduler_t *sched = engine->scheduler;
355 ASSERT_NOT_NULL(sched);
356
357 fiber_yield_n = 0;
358 (void)srn_fiber_spawn(ctx, fiber_yield_entry, (void *)(intptr_t)1);
359 (void)srn_fiber_spawn(ctx, fiber_yield_entry, (void *)(intptr_t)2);
360
361 srn_sched_run(sched, 1);
362
364 int ones = 0;
365 int twos = 0;
366 for (int i = 0; i < 4; i++) {
367 if (fiber_yield_log[i] == 1) {
368 ones++;
369 } else if (fiber_yield_log[i] == 2) {
370 twos++;
371 }
372 }
373 TEST_CHECK(ones == 2);
374 TEST_CHECK(twos == 2);
375
376 RELEASE_CONTEXT(ctx);
377 SHUTDOWN_ENGINE(mm, engine);
378}
static srn_fiber_result_t fiber_yield_entry(srn_context_t *ctx, void *arg)
Here is the call graph for this function:

◆ test_fiber_sched_yield_round_robin()

void test_fiber_sched_yield_round_robin ( )
static

Definition at line 398 of file fiber_tests.h.

398 {
399 MAKE_ENGINE(mm, engine);
400 MAKE_CONTEXT(engine, ctx);
401 srn_scheduler_t *sched = engine->scheduler;
402 ASSERT_NOT_NULL(sched);
403
404 fiber_rr_n = 0;
405 (void)srn_fiber_spawn(ctx, fiber_rr_entry, (void *)(intptr_t)1);
406 (void)srn_fiber_spawn(ctx, fiber_rr_entry, (void *)(intptr_t)2);
407
408 srn_sched_run(sched, 1);
409
411 // Strict alternation, a yielding fiber never runs two steps back to back
412 // while a peer is ready.
413 for (int i = 1; i < 6; i++) {
415 TEST_MSG(
416 "order: %d %d %d %d %d %d", fiber_rr_log[0], fiber_rr_log[1], fiber_rr_log[2],
418 );
419 }
420
421 RELEASE_CONTEXT(ctx);
422 SHUTDOWN_ENGINE(mm, engine);
423}
#define TEST_MSG(...)
Definition acutest.h:223
static srn_fiber_result_t fiber_rr_entry(srn_context_t *ctx, void *arg)
Here is the call graph for this function:

◆ test_fiber_spawn_copy()

void test_fiber_spawn_copy ( )
static

Definition at line 160 of file fiber_tests.h.

160 {
161 MAKE_ENGINE(mm, engine);
162 MAKE_CONTEXT(engine, ctx);
163 srn_scheduler_t *sched = engine->scheduler;
164
165 spawn_copy_seen = 0;
166 {
167 spawn_copy_args_t args = {.value = 4242};
169 }
170
171 srn_sched_run(sched, 1);
173
174 RELEASE_CONTEXT(ctx);
175 SHUTDOWN_ENGINE(mm, engine);
176}
va_list args
Definition acutest.h:876
#define SRN_FIBER_SPAWN_COPY(ctx, entry, value)
srn_fiber_spawn_copy for an lvalue, the address and size are taken for the caller.
Definition fiber.h:474
static srn_fiber_result_t spawn_copy_entry(srn_context_t *ctx, void *arg)
Here is the call graph for this function:

◆ test_fiber_stack()

void test_fiber_stack ( )
static

Definition at line 224 of file fiber_tests.h.

224 {
225 size_t page = srn_mm_get_os_page_size();
226
228
229 TEST_CHECK(s.guard != nullptr);
230 TEST_CHECK(s.limit != nullptr);
231 TEST_CHECK(s.start != nullptr);
232 // The guard sits exactly one page below the usable region.
233 TEST_CHECK((char *)s.limit == (char *)s.guard + page);
234 // The usable region is non-empty, page-aligned, and at least the default.
235 TEST_CHECK((char *)s.start > (char *)s.limit);
236 TEST_CHECK(((uintptr_t)s.limit & (page - 1)) == 0);
238
239 // The whole usable region is writable end to end. The guard is left alone.
240 ((char *)s.limit)[0] = (char)0x5A;
241 ((char *)s.start)[-1] = (char)0x5A;
242
244}
size_t srn_mm_get_os_page_size(void)
Retutrns the OS page size.
Definition default.c:313
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...
static size_t srn_fiber_stack_size(srn_fiber_stack_t s)
Definition fiber.h:625
void srn_fiber_stack_free(srn_fiber_stack_t stack)
#define SRN_FIBER_DEFAULT_STACK_SIZE
Default size of every fiber stack.
Definition fiber.h:184
One stack per fiber, mapped with a guard page at the low end so an overflow faults deterministically ...
Definition fiber.h:222
void * guard
The protected page to detect stack overflows.
Definition fiber.h:228
void * limit
Low end of usable region.
Definition fiber.h:226
void * start
High end, stack pointer initialises to this address.
Definition fiber.h:224
Here is the call graph for this function:

◆ test_fiber_switch()

void test_fiber_switch ( )
static

Definition at line 266 of file fiber_tests.h.

266 {
268
270
272 fiber_pp_worker.stack = worker_stack;
274 srn_fiber_ctx_make(&fiber_pp_worker.fiber_ctx, worker_stack, fiber_pp_entry, nullptr);
275
276 fiber_pp_ticks = 0;
277 fiber_pp_rounds = 5;
278
279 // `rounds` yields, plus one more switch to let the worker run to completion.
280 for (int i = 0; i <= fiber_pp_rounds; i++) {
282 }
283
286
287 srn_fiber_stack_free(worker_stack);
288}
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:153
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...
@ SRN_FIBER_RUNNING
Currently executing.
Definition fiber.h:240
static void fiber_pp_entry(void *arg)
Here is the call graph for this function:

◆ test_fiber_thread_stack_bounds()

void test_fiber_thread_stack_bounds ( )
static

Definition at line 56 of file fiber_tests.h.

56 {
57 srn_fiber_t loop;
60#if SRN_ASAN
61 TEST_CHECK(loop.stack.limit != nullptr);
62 TEST_CHECK(loop.stack.start != nullptr);
63 // A local's address cannot anchor the check, ASan's fake stack moves
64 // address taken locals off the real thread stack. Sanity of the reported
65 // range is what is checkable, ordered bounds spanning at least one page.
67#else
68 TEST_CHECK(loop.stack.limit == nullptr);
69#endif
70}
srn_fiber_stack_t stack
Definition fiber.h:271
Here is the call graph for this function:

◆ test_fiber_types()

void test_fiber_types ( )
static

Definition at line 209 of file fiber_tests.h.

209 {
210 // Smoke test, the public types exist and the build/test wiring works.
211 // The saved context is a single stack-pointer word.
212 TEST_CHECK(sizeof(srn_fiber_ctx_t) == sizeof(void *));
213 // The lifecycle states run from creation to completion in order.
219}
@ SRN_FIBER_READY
On the run queue, eligible to run.
Definition fiber.h:238
The saved context of a suspended fiber is a single word, its stack pointer at the moment it was switc...
Definition fiber.h:202

Variable Documentation

◆ auto_name_child

srn_fiber_t* auto_name_child
static

Definition at line 78 of file fiber_tests.h.

◆ auto_workers_ran

atomic_int auto_workers_ran
static

Definition at line 178 of file fiber_tests.h.

◆ fiber_dwake_runs

int fiber_dwake_runs
static

Definition at line 560 of file fiber_tests.h.

◆ fiber_dwake_signalled

bool fiber_dwake_signalled
static

Definition at line 559 of file fiber_tests.h.

◆ fiber_dwake_waiter

srn_fiber_t* fiber_dwake_waiter
static

Definition at line 558 of file fiber_tests.h.

◆ fiber_mbox

fiber_mbox_t fiber_mbox
static

Definition at line 434 of file fiber_tests.h.

◆ fiber_mbox_got

int fiber_mbox_got
static

Definition at line 435 of file fiber_tests.h.

◆ fiber_mt_counter

atomic_int fiber_mt_counter
static

Definition at line 713 of file fiber_tests.h.

◆ fiber_mt_yield_counter

atomic_int fiber_mt_yield_counter
static

Definition at line 746 of file fiber_tests.h.

◆ fiber_ok_value

int fiber_ok_value
static

Definition at line 292 of file fiber_tests.h.

◆ fiber_pp_rounds

int fiber_pp_rounds
static

Definition at line 254 of file fiber_tests.h.

◆ fiber_pp_thread

srn_fiber_t fiber_pp_thread
static

Definition at line 251 of file fiber_tests.h.

◆ fiber_pp_ticks

int fiber_pp_ticks
static

Definition at line 253 of file fiber_tests.h.

◆ fiber_pp_worker

srn_fiber_t fiber_pp_worker
static

Definition at line 252 of file fiber_tests.h.

◆ fiber_rr_log

int fiber_rr_log[6]
static

Definition at line 383 of file fiber_tests.h.

◆ fiber_rr_n

int fiber_rr_n
static

Definition at line 384 of file fiber_tests.h.

◆ fiber_run_counter

int fiber_run_counter
static

Definition at line 297 of file fiber_tests.h.

◆ fiber_stop_rounds

atomic_int fiber_stop_rounds
static

Definition at line 784 of file fiber_tests.h.

◆ fiber_wf_result

int fiber_wf_result
static

Definition at line 617 of file fiber_tests.h.

◆ fiber_wf_seen

srn_fiber_result_t fiber_wf_seen
static

Definition at line 619 of file fiber_tests.h.

◆ fiber_wf_target

srn_fiber_t* fiber_wf_target
static

Definition at line 618 of file fiber_tests.h.

◆ fiber_wf_woke

int fiber_wf_woke
static

Definition at line 676 of file fiber_tests.h.

◆ fiber_yield_log

int fiber_yield_log[4]
static

Definition at line 338 of file fiber_tests.h.

◆ fiber_yield_n

int fiber_yield_n
static

Definition at line 339 of file fiber_tests.h.

◆ spawn_copy_seen

int spawn_copy_seen
static

Definition at line 149 of file fiber_tests.h.