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:250
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 449 of file fiber_tests.h.

449 {
450 UNUSED(ctx);
451 UNUSED(arg);
454 return &fiber_ok_value;
455}
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 572 of file fiber_tests.h.

572 {
573 UNUSED(ctx);
574 UNUSED(arg);
577 return &fiber_ok_value;
578}
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 563 of file fiber_tests.h.

563 {
564 UNUSED(arg);
566 return false;
567 }
568 fiber_dwake_waiter = self;
569 return true;
570}
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 580 of file fiber_tests.h.

580 {
581 UNUSED(ctx);
582 UNUSED(arg);
584 if (fiber_dwake_waiter != nullptr) {
586 fiber_dwake_waiter = nullptr;
587 srn_fiber_ready(w); // first waker: SUSPENDED -> READY, enqueued
588 srn_fiber_ready(w); // second waker: already READY -> no-op
589 }
590 return &fiber_ok_value;
591}
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 440 of file fiber_tests.h.

440 {
441 fiber_mbox_t *mb = arg;
442 if (mb->has_value) {
443 return false;
444 }
445 mb->waiter = self;
446 return true;
447}
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 716 of file fiber_tests.h.

716 {
717 UNUSED(ctx);
718 UNUSED(arg);
719 atomic_fetch_add(&fiber_mt_counter, 1);
720 return &fiber_ok_value;
721}
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 749 of file fiber_tests.h.

749 {
750 UNUSED(ctx);
751 int rounds = (int)(intptr_t)arg;
752 for (int i = 0; i < rounds; i++) {
753 atomic_fetch_add(&fiber_mt_yield_counter, 1);
755 }
756 return &fiber_ok_value;
757}
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 799 of file fiber_tests.h.

799 {
800 UNUSED(ctx);
801 UNUSED(arg);
802 // Never reached, the stopper ends the run first. It adds a large amount, so
803 // any accidental execution is visible in the count.
804 atomic_fetch_add(&fiber_stop_rounds, 1000);
805 return &fiber_ok_value;
806}
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 257 of file fiber_tests.h.

257 {
258 UNUSED(arg);
260 for (int i = 0; i < fiber_pp_rounds; i++) {
263 }
265}
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 457 of file fiber_tests.h.

457 {
458 UNUSED(ctx);
459 UNUSED(arg);
460 fiber_mbox.value = 42;
461 fiber_mbox.has_value = true;
462 if (fiber_mbox.waiter != nullptr) {
463 srn_fiber_t *w = fiber_mbox.waiter;
464 fiber_mbox.waiter = nullptr;
466 }
467 return &fiber_ok_value;
468}
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 387 of file fiber_tests.h.

387 {
388 UNUSED(ctx);
389 int id = (int)(intptr_t)arg;
390 for (int i = 0; i < 3; i++) {
391 if (fiber_rr_n < 6) {
392 fiber_rr_log[fiber_rr_n++] = id;
393 }
395 }
396 return &fiber_ok_value;
397}
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 300 of file fiber_tests.h.

300 {
301 UNUSED(ctx);
302 UNUSED(arg);
304 return &fiber_ok_value;
305}
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 787 of file fiber_tests.h.

787 {
788 UNUSED(ctx);
789 srn_scheduler_t *sched = arg;
790 // No yield in this loop, a yielded fiber goes to the back of the queue, so
791 // yielding would hand the pending fibers a turn before the stop lands.
792 for (int i = 0; i < 3; i++) {
793 atomic_fetch_add(&fiber_stop_rounds, 1);
794 }
795 srn_sched_stop(sched);
796 return &fiber_ok_value;
797}
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 528 of file fiber_tests.h.

528 {
529 UNUSED(ctx);
530 UNUSED(arg);
531 srn_fiber_suspend(fiber_stuck_park, nullptr); // never readied
532 return &fiber_ok_value;
533}
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 522 of file fiber_tests.h.

522 {
523 UNUSED(self);
524 UNUSED(arg);
525 return true; // stay parked, with no waker
526}
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 679 of file fiber_tests.h.

679 {
680 UNUSED(ctx);
681 UNUSED(arg);
684 }
685 return &fiber_ok_value;
686}
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 622 of file fiber_tests.h.

622 {
623 UNUSED(ctx);
624 UNUSED(arg);
625 return &fiber_wf_result;
626}
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 628 of file fiber_tests.h.

628 {
629 UNUSED(ctx);
630 UNUSED(arg);
632 return &fiber_ok_value;
633}
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 342 of file fiber_tests.h.

342 {
343 UNUSED(ctx);
344 int id = (int)(intptr_t)arg;
345 for (int i = 0; i < 2; i++) {
348 }
349 return &fiber_ok_value;
350}
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:48
#define SHUTDOWN_ENGINE(mm, engine)
Definition base.h:40
#define MAKE_ENGINE(mm, engine)
Definition base.h:34
#define MAKE_CONTEXT(engine, x)
Definition base.h:44
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:318
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:202
@ SRN_FIBER_NEW
Created, stack mapped, never resumed.
Definition fiber.h:221
@ SRN_FIBER_DONE
Entry returned. The result is final.
Definition fiber.h:229
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:262
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 593 of file fiber_tests.h.

593 {
594 MAKE_ENGINE(mm, engine);
595 MAKE_CONTEXT(engine, ctx);
596 srn_scheduler_t *sched = engine->scheduler;
597 ASSERT_NOT_NULL(sched);
598
599 fiber_dwake_waiter = nullptr;
600 fiber_dwake_signalled = false;
602
603 // Consumer first, so it runs and suspends before the producer wakes it.
604 (void)srn_fiber_spawn(ctx, fiber_dwake_consumer_entry, nullptr);
605 (void)srn_fiber_spawn(ctx, fiber_dwake_producer_entry, nullptr);
606
607 srn_sched_run(sched, 1);
608
610
611 RELEASE_CONTEXT(ctx);
612 SHUTDOWN_ENGINE(mm, engine);
613}
#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 723 of file fiber_tests.h.

723 {
724 MAKE_ENGINE(mm, engine);
725 MAKE_CONTEXT(engine, ctx);
726 srn_scheduler_t *sched = engine->scheduler;
727 ASSERT_NOT_NULL(sched);
728
729 atomic_store(&fiber_mt_counter, 0);
730 enum { N = 256 };
731 for (int i = 0; i < N; i++) {
732 (void)srn_fiber_spawn(ctx, fiber_mt_entry, nullptr);
733 }
734
735 srn_sched_run(sched, 4);
736
737 TEST_CHECK(atomic_load(&fiber_mt_counter) == N);
738
739 RELEASE_CONTEXT(ctx);
740 SHUTDOWN_ENGINE(mm, engine);
741}
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 759 of file fiber_tests.h.

759 {
760 MAKE_ENGINE(mm, engine);
761 MAKE_CONTEXT(engine, ctx);
762 srn_scheduler_t *sched = engine->scheduler;
763 ASSERT_NOT_NULL(sched);
764
765 atomic_store(&fiber_mt_yield_counter, 0);
766 enum { N = 64, ROUNDS = 8 };
767 for (int i = 0; i < N; i++) {
768 (void)srn_fiber_spawn(ctx, fiber_mt_yield_entry, (void *)(intptr_t)ROUNDS);
769 }
770
771 srn_sched_run(sched, 4);
772
773 TEST_CHECK(atomic_load(&fiber_mt_yield_counter) == N * ROUNDS);
774
775 RELEASE_CONTEXT(ctx);
776 SHUTDOWN_ENGINE(mm, engine);
777}
#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 495 of file fiber_tests.h.

495 {
496 MAKE_ENGINE(mm, engine);
497 MAKE_CONTEXT(engine, ctx);
498 srn_scheduler_t *sched = engine->scheduler;
499 ASSERT_NOT_NULL(sched);
500
502 fiber_mbox.value = 7;
503 fiber_mbox.has_value = true; // value present before the consumer runs
504 fiber_mbox_got = 0;
505
506 (void)srn_fiber_spawn(ctx, fiber_consumer_entry, nullptr);
507
508 srn_sched_run(sched, 1);
509
511 TEST_CHECK(fiber_mbox.waiter == nullptr); // never registered as a waiter
512
513 RELEASE_CONTEXT(ctx);
514 SHUTDOWN_ENGINE(mm, engine);
515}
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 535 of file fiber_tests.h.

535 {
536 MAKE_ENGINE(mm, engine);
537 MAKE_CONTEXT(engine, ctx);
538 srn_scheduler_t *sched = engine->scheduler;
539 ASSERT_NOT_NULL(sched);
540
541 srn_fiber_t *stuck = srn_fiber_spawn(ctx, fiber_stuck_entry, nullptr);
542 ASSERT_NOT_NULL(stuck);
543
544 // Drains the ready queue. The stuck fiber suspends and is abandoned.
545 srn_sched_run(sched, 1);
547
548 // The registry lets shutdown find and free the abandoned fiber's stack.
549 srn_sched_shutdown(sched);
550
551 RELEASE_CONTEXT(ctx);
552 SHUTDOWN_ENGINE(mm, engine);
553}
@ SRN_FIBER_SUSPENDED
Parked off the run queue, awaits srn_fiber_ready.
Definition fiber.h:227
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 307 of file fiber_tests.h.

307 {
308 MAKE_ENGINE(mm, engine);
309 MAKE_CONTEXT(engine, ctx);
310 srn_scheduler_t *sched = engine->scheduler;
311 ASSERT_NOT_NULL(sched);
312
314 enum { N = 4 };
315 srn_fiber_t *fibers[N];
316 for (int i = 0; i < N; i++) {
317 fibers[i] = srn_fiber_spawn(ctx, fiber_run_entry, nullptr);
318 ASSERT_NOT_NULL(fibers[i]);
319 }
320
321 srn_sched_run(sched, 1);
322
324 for (int i = 0; i < N; i++) {
325 // The struct lives in the context block after reaping. Only the stack is
326 // released, so state and result are still readable here.
327 TEST_CHECK(fibers[i]->state == SRN_FIBER_DONE);
328 TEST_CHECK(fibers[i]->result == &fiber_ok_value);
329 }
330
331 RELEASE_CONTEXT(ctx);
332 SHUTDOWN_ENGINE(mm, engine);
333}
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 808 of file fiber_tests.h.

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

470 {
471 MAKE_ENGINE(mm, engine);
472 MAKE_CONTEXT(engine, ctx);
473 srn_scheduler_t *sched = engine->scheduler;
474 ASSERT_NOT_NULL(sched);
475
477 fiber_mbox_got = 0;
478
479 // Order matters, the consumer must be enqueued first so it runs and suspends
480 // before the producer fills the slot.
481 (void)srn_fiber_spawn(ctx, fiber_consumer_entry, nullptr);
482 (void)srn_fiber_spawn(ctx, fiber_producer_entry, nullptr);
483
484 srn_sched_run(sched, 1);
485
487
488 RELEASE_CONTEXT(ctx);
489 SHUTDOWN_ENGINE(mm, engine);
490}
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 635 of file fiber_tests.h.

635 {
636 MAKE_ENGINE(mm, engine);
637 MAKE_CONTEXT(engine, ctx);
638 srn_scheduler_t *sched = engine->scheduler;
639 ASSERT_NOT_NULL(sched);
640
641 fiber_wf_seen = nullptr;
642 // Waiter made first, so it runs and parks before the target finishes.
643 (void)srn_fiber_spawn(ctx, fiber_wf_waiter_entry, nullptr);
645
646 srn_sched_run(sched, 1);
647
649
650 RELEASE_CONTEXT(ctx);
651 SHUTDOWN_ENGINE(mm, engine);
652}
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 656 of file fiber_tests.h.

656 {
657 MAKE_ENGINE(mm, engine);
658 MAKE_CONTEXT(engine, ctx);
659 srn_scheduler_t *sched = engine->scheduler;
660 ASSERT_NOT_NULL(sched);
661
662 fiber_wf_seen = nullptr;
663 // Target made first, so it runs and finishes before the waiter runs.
665 (void)srn_fiber_spawn(ctx, fiber_wf_waiter_entry, nullptr);
666
667 srn_sched_run(sched, 1);
668
670
671 RELEASE_CONTEXT(ctx);
672 SHUTDOWN_ENGINE(mm, engine);
673}
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 688 of file fiber_tests.h.

688 {
689 MAKE_ENGINE(mm, engine);
690 MAKE_CONTEXT(engine, ctx);
691 srn_scheduler_t *sched = engine->scheduler;
692 ASSERT_NOT_NULL(sched);
693
694 fiber_wf_woke = 0;
695 // Three waiters made first so they all park, then the target finishes.
696 (void)srn_fiber_spawn(ctx, fiber_wf_counting_waiter, nullptr);
697 (void)srn_fiber_spawn(ctx, fiber_wf_counting_waiter, nullptr);
698 (void)srn_fiber_spawn(ctx, fiber_wf_counting_waiter, nullptr);
700
701 srn_sched_run(sched, 1);
702
704
705 RELEASE_CONTEXT(ctx);
706 SHUTDOWN_ENGINE(mm, engine);
707}
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 352 of file fiber_tests.h.

352 {
353 MAKE_ENGINE(mm, engine);
354 MAKE_CONTEXT(engine, ctx);
355 srn_scheduler_t *sched = engine->scheduler;
356 ASSERT_NOT_NULL(sched);
357
358 fiber_yield_n = 0;
359 (void)srn_fiber_spawn(ctx, fiber_yield_entry, (void *)(intptr_t)1);
360 (void)srn_fiber_spawn(ctx, fiber_yield_entry, (void *)(intptr_t)2);
361
362 srn_sched_run(sched, 1);
363
365 int ones = 0;
366 int twos = 0;
367 for (int i = 0; i < 4; i++) {
368 if (fiber_yield_log[i] == 1) {
369 ones++;
370 } else if (fiber_yield_log[i] == 2) {
371 twos++;
372 }
373 }
374 TEST_CHECK(ones == 2);
375 TEST_CHECK(twos == 2);
376
377 RELEASE_CONTEXT(ctx);
378 SHUTDOWN_ENGINE(mm, engine);
379}
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 399 of file fiber_tests.h.

399 {
400 MAKE_ENGINE(mm, engine);
401 MAKE_CONTEXT(engine, ctx);
402 srn_scheduler_t *sched = engine->scheduler;
403 ASSERT_NOT_NULL(sched);
404
405 fiber_rr_n = 0;
406 (void)srn_fiber_spawn(ctx, fiber_rr_entry, (void *)(intptr_t)1);
407 (void)srn_fiber_spawn(ctx, fiber_rr_entry, (void *)(intptr_t)2);
408
409 srn_sched_run(sched, 1);
410
412 // Strict alternation, a yielding fiber never runs two steps back to back
413 // while a peer is ready.
414 for (int i = 1; i < 6; i++) {
416 TEST_MSG(
417 "order: %d %d %d %d %d %d", fiber_rr_log[0], fiber_rr_log[1], fiber_rr_log[2],
419 );
420 }
421
422 RELEASE_CONTEXT(ctx);
423 SHUTDOWN_ENGINE(mm, engine);
424}
#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:459
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 size_t guard_pages = 4;
227
228 srn_fiber_stack_t s = srn_fiber_stack_alloc(0, guard_pages);
229
230 TEST_CHECK(s.guard != nullptr);
231 TEST_CHECK(s.limit != nullptr);
232 TEST_CHECK(s.start != nullptr);
233 // The guard band spans the requested number of pages below the usable region.
234 TEST_CHECK((char *)s.limit == (char *)s.guard + guard_pages * page);
235 // The usable region is non-empty, page-aligned, and at least the default.
236 TEST_CHECK((char *)s.start > (char *)s.limit);
237 TEST_CHECK(((uintptr_t)s.limit & (page - 1)) == 0);
239
240 // The whole usable region is writable end to end. The guard is left alone.
241 ((char *)s.limit)[0] = (char)0x5A;
242 ((char *)s.start)[-1] = (char)0x5A;
243
245}
#define SRN_CONFIG_DEFAULT_FIBER_STACK_SIZE
Size of every fiber stack, in bytes.
size_t srn_mm_get_os_page_size(void)
Retutrns the OS page size.
Definition default.c:312
srn_fiber_stack_t srn_fiber_stack_alloc(size_t size, size_t guard_pages)
Allocate a stack of at least size usable bytes, or SRN_CONFIG_DEFAULT_FIBER_STACK_SIZE when size is 0...
static size_t srn_fiber_stack_size(srn_fiber_stack_t s)
Definition fiber.h:612
void srn_fiber_stack_free(srn_fiber_stack_t stack)
One stack per fiber, mapped with a guard band at the low end so an overflow faults deterministically ...
Definition fiber.h:207
void * guard
Low base of the protected guard band that detects stack overflows.
Definition fiber.h:213
void * limit
Low end of usable region.
Definition fiber.h:211
void * start
High end, stack pointer initialises to this address.
Definition fiber.h:209
Here is the call graph for this function:

◆ test_fiber_switch()

void test_fiber_switch ( )
static

Definition at line 267 of file fiber_tests.h.

267 {
269
271
273 fiber_pp_worker.stack = worker_stack;
275 srn_fiber_ctx_make(&fiber_pp_worker.fiber_ctx, worker_stack, fiber_pp_entry, nullptr);
276
277 fiber_pp_ticks = 0;
278 fiber_pp_rounds = 5;
279
280 // `rounds` yields, plus one more switch to let the worker run to completion.
281 for (int i = 0; i <= fiber_pp_rounds; i++) {
283 }
284
287
288 srn_fiber_stack_free(worker_stack);
289}
#define SRN_CONFIG_DEFAULT_FIBER_GUARD_PAGES
Pages in the guard band below every fiber stack.
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:225
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:256
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:223
The saved context of a suspended fiber is a single word, its stack pointer at the moment it was switc...
Definition fiber.h:187

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 561 of file fiber_tests.h.

◆ fiber_dwake_signalled

bool fiber_dwake_signalled
static

Definition at line 560 of file fiber_tests.h.

◆ fiber_dwake_waiter

srn_fiber_t* fiber_dwake_waiter
static

Definition at line 559 of file fiber_tests.h.

◆ fiber_mbox

fiber_mbox_t fiber_mbox
static

Definition at line 435 of file fiber_tests.h.

◆ fiber_mbox_got

int fiber_mbox_got
static

Definition at line 436 of file fiber_tests.h.

◆ fiber_mt_counter

atomic_int fiber_mt_counter
static

Definition at line 714 of file fiber_tests.h.

◆ fiber_mt_yield_counter

atomic_int fiber_mt_yield_counter
static

Definition at line 747 of file fiber_tests.h.

◆ fiber_ok_value

int fiber_ok_value
static

Definition at line 293 of file fiber_tests.h.

◆ fiber_pp_rounds

int fiber_pp_rounds
static

Definition at line 255 of file fiber_tests.h.

◆ fiber_pp_thread

srn_fiber_t fiber_pp_thread
static

Definition at line 252 of file fiber_tests.h.

◆ fiber_pp_ticks

int fiber_pp_ticks
static

Definition at line 254 of file fiber_tests.h.

◆ fiber_pp_worker

srn_fiber_t fiber_pp_worker
static

Definition at line 253 of file fiber_tests.h.

◆ fiber_rr_log

int fiber_rr_log[6]
static

Definition at line 384 of file fiber_tests.h.

◆ fiber_rr_n

int fiber_rr_n
static

Definition at line 385 of file fiber_tests.h.

◆ fiber_run_counter

int fiber_run_counter
static

Definition at line 298 of file fiber_tests.h.

◆ fiber_stop_rounds

atomic_int fiber_stop_rounds
static

Definition at line 785 of file fiber_tests.h.

◆ fiber_wf_result

int fiber_wf_result
static

Definition at line 618 of file fiber_tests.h.

◆ fiber_wf_seen

srn_fiber_result_t fiber_wf_seen
static

Definition at line 620 of file fiber_tests.h.

◆ fiber_wf_target

srn_fiber_t* fiber_wf_target
static

Definition at line 619 of file fiber_tests.h.

◆ fiber_wf_woke

int fiber_wf_woke
static

Definition at line 677 of file fiber_tests.h.

◆ fiber_yield_log

int fiber_yield_log[4]
static

Definition at line 339 of file fiber_tests.h.

◆ fiber_yield_n

int fiber_yield_n
static

Definition at line 340 of file fiber_tests.h.

◆ spawn_copy_seen

int spawn_copy_seen
static

Definition at line 149 of file fiber_tests.h.