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/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 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 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 int spawn_copy_seen
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::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_stack()
static void test_fiber_thread_stack_bounds()
Definition fiber_tests.h:54
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:79
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 29 of file fiber_tests.h.

29#define FIBER_TESTS(X) \
30 X("fiber::types", test_fiber_types), X("fiber::switch", test_fiber_switch), \
31 X("fiber::stack", test_fiber_stack), \
32 X("fiber::thread_stack_bounds", test_fiber_thread_stack_bounds), \
33 X("fiber::auto_name", test_fiber_auto_name), \
34 X("fiber::make_schedule", test_fiber_make_schedule), \
35 X("fiber::spawn_copy", test_fiber_spawn_copy), X("fiber::sched::run", test_fiber_sched_run), \
36 X("fiber::sched::yield", test_fiber_sched_yield), \
37 X("fiber::sched::yield_round_robin", test_fiber_sched_yield_round_robin), \
38 X("fiber::sched::suspend", test_fiber_sched_suspend), \
39 X("fiber::sched::park_abort", test_fiber_sched_park_abort), \
40 X("fiber::sched::registry", test_fiber_sched_registry), \
41 X("fiber::sched::double_wake", test_fiber_sched_double_wake), \
42 X("fiber::sched::wait_for", test_fiber_sched_wait_for), \
43 X("fiber::sched::wait_for_done", test_fiber_sched_wait_for_done), \
44 X("fiber::sched::wait_for_many", test_fiber_sched_wait_for_many), \
45 X("fiber::sched::mt_run", test_fiber_sched_mt_run), \
46 X("fiber::sched::mt_yield", test_fiber_sched_mt_yield), \
47 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 70 of file fiber_tests.h.

70 {
71 UNUSED(ctx);
72 UNUSED(arg);
73 return nullptr;
74}
#define UNUSED(x)
Definition utils.h:45
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 398 of file fiber_tests.h.

398 {
399 UNUSED(ctx);
400 UNUSED(arg);
403 return &fiber_ok_value;
404}
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:1024
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 521 of file fiber_tests.h.

521 {
522 UNUSED(ctx);
523 UNUSED(arg);
526 return &fiber_ok_value;
527}
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 512 of file fiber_tests.h.

512 {
513 UNUSED(arg);
515 return false;
516 }
517 fiber_dwake_waiter = self;
518 return true;
519}
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 529 of file fiber_tests.h.

529 {
530 UNUSED(ctx);
531 UNUSED(arg);
533 if (fiber_dwake_waiter != nullptr) {
535 fiber_dwake_waiter = nullptr;
536 srn_fiber_ready(w); // first waker: SUSPENDED -> READY, enqueued
537 srn_fiber_ready(w); // second waker: already READY -> no-op
538 }
539 return &fiber_ok_value;
540}
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:1044
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 389 of file fiber_tests.h.

389 {
390 fiber_mbox_t *mb = arg;
391 if (mb->has_value) {
392 return false;
393 }
394 mb->waiter = self;
395 return true;
396}
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 665 of file fiber_tests.h.

665 {
666 UNUSED(ctx);
667 UNUSED(arg);
668 atomic_fetch_add(&fiber_mt_counter, 1);
669 return &fiber_ok_value;
670}
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 698 of file fiber_tests.h.

698 {
699 UNUSED(ctx);
700 int rounds = (int)(intptr_t)arg;
701 for (int i = 0; i < rounds; i++) {
702 atomic_fetch_add(&fiber_mt_yield_counter, 1);
704 }
705 return &fiber_ok_value;
706}
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:1000
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 748 of file fiber_tests.h.

748 {
749 UNUSED(ctx);
750 UNUSED(arg);
751 // Never reached, the stopper ends the run first. It adds a large amount, so
752 // any accidental execution is visible in the count.
753 atomic_fetch_add(&fiber_stop_rounds, 1000);
754 return &fiber_ok_value;
755}
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 206 of file fiber_tests.h.

206 {
207 UNUSED(arg);
209 for (int i = 0; i < fiber_pp_rounds; i++) {
212 }
214}
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:88
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:66
void srn_fiber_on_entry(srn_fiber_t *from)
Call as the first action inside a fresh fiber's entry.
Definition fiber.c:111
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 406 of file fiber_tests.h.

406 {
407 UNUSED(ctx);
408 UNUSED(arg);
409 fiber_mbox.value = 42;
410 fiber_mbox.has_value = true;
411 if (fiber_mbox.waiter != nullptr) {
412 srn_fiber_t *w = fiber_mbox.waiter;
413 fiber_mbox.waiter = nullptr;
415 }
416 return &fiber_ok_value;
417}
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 336 of file fiber_tests.h.

336 {
337 UNUSED(ctx);
338 int id = (int)(intptr_t)arg;
339 for (int i = 0; i < 3; i++) {
340 if (fiber_rr_n < 6) {
341 fiber_rr_log[fiber_rr_n++] = id;
342 }
344 }
345 return &fiber_ok_value;
346}
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 249 of file fiber_tests.h.

249 {
250 UNUSED(ctx);
251 UNUSED(arg);
253 return &fiber_ok_value;
254}
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 736 of file fiber_tests.h.

736 {
737 UNUSED(ctx);
738 srn_scheduler_t *sched = arg;
739 // No yield in this loop, a yielded fiber goes to the back of the queue, so
740 // yielding would hand the pending fibers a turn before the stop lands.
741 for (int i = 0; i < 3; i++) {
742 atomic_fetch_add(&fiber_stop_rounds, 1);
743 }
744 srn_sched_stop(sched);
745 return &fiber_ok_value;
746}
void srn_sched_stop(srn_scheduler_t *sched)
Ask a running scheduler to stop.
Definition scheduler.c:939
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 477 of file fiber_tests.h.

477 {
478 UNUSED(ctx);
479 UNUSED(arg);
480 srn_fiber_suspend(fiber_stuck_park, nullptr); // never readied
481 return &fiber_ok_value;
482}
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 471 of file fiber_tests.h.

471 {
472 UNUSED(self);
473 UNUSED(arg);
474 return true; // stay parked, with no waker
475}
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 628 of file fiber_tests.h.

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

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

577 {
578 UNUSED(ctx);
579 UNUSED(arg);
581 return &fiber_ok_value;
582}
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 291 of file fiber_tests.h.

291 {
292 UNUSED(ctx);
293 int id = (int)(intptr_t)arg;
294 for (int i = 0; i < 2; i++) {
297 }
298 return &fiber_ok_value;
299}
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 132 of file fiber_tests.h.

132 {
133 UNUSED(ctx);
134 spawn_copy_seen = ((spawn_copy_args_t *)arg)->value;
135 return nullptr;
136}
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 79 of file fiber_tests.h.

79 {
80 MAKE_ENGINE(mm, engine);
81 MAKE_CONTEXT(engine, ctx);
82 srn_scheduler_t *sched = engine->scheduler;
83
86
87 TEST_CHECK(strncmp(a->name, "f#", 2) == 0);
88 TEST_CHECK(strncmp(b->name, "f#", 2) == 0);
89 TEST_CHECK(strcmp(a->name, b->name) != 0);
90
91 // Run the fibers so the registry is empty before the context goes away.
92 srn_sched_run(sched, 1);
93
94 RELEASE_CONTEXT(ctx);
95 SHUTDOWN_ENGINE(mm, engine);
96}
#define TEST_CHECK(cond)
Definition acutest.h:95
#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
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:247
static srn_fiber_result_t auto_name_entry(srn_context_t *ctx, void *arg)
Definition fiber_tests.h:70
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:843
char name[SRN_FIBER_NAME_MAX]
Debug name, the caller's choice copied at creation, or the autogenerated f#<id> from the engine wide ...
Definition fiber.h:330
Here is the call graph for this function:

◆ test_fiber_make_schedule()

void test_fiber_make_schedule ( )
static

Definition at line 101 of file fiber_tests.h.

101 {
102 MAKE_ENGINE(mm, engine);
103 MAKE_CONTEXT(engine, ctx);
104 srn_scheduler_t *sched = engine->scheduler;
105
106 srn_fiber_t *stay = srn_fiber_make(ctx, sched, "left-new", auto_name_entry, nullptr, 0);
107 srn_fiber_t *go = srn_fiber_make(ctx, sched, "scheduled", auto_name_entry, nullptr, 0);
108
110 TEST_CHECK(strcmp(go->name, "scheduled") == 0);
111 TEST_CHECK(strcmp(stay->name, "left-new") == 0);
112
114 srn_sched_run(sched, 1);
115
118
119 // Reap the never scheduled fiber while its struct (in the context block)
120 // is still alive, before releasing the context.
121 srn_sched_shutdown(sched);
122 RELEASE_CONTEXT(ctx);
123 SHUTDOWN_ENGINE(mm, engine);
124}
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:201
@ SRN_FIBER_NEW
Created, stack mapped, never resumed.
Definition fiber.h:232
@ SRN_FIBER_DONE
Entry returned. The result is final.
Definition fiber.h:240
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:327
void srn_fiber_schedule(srn_fiber_t *fiber)
Schedule a NEW fiber, making it eligible to run.
Definition scheduler.c:630
_Atomic srn_fiber_state_t state
The lifecycle state.
Definition fiber.h:273
Here is the call graph for this function:

◆ test_fiber_sched_double_wake()

void test_fiber_sched_double_wake ( )
static

Definition at line 542 of file fiber_tests.h.

542 {
543 MAKE_ENGINE(mm, engine);
544 MAKE_CONTEXT(engine, ctx);
545 srn_scheduler_t *sched = engine->scheduler;
546 ASSERT_NOT_NULL(sched);
547
548 fiber_dwake_waiter = nullptr;
549 fiber_dwake_signalled = false;
551
552 // Consumer first, so it runs and suspends before the producer wakes it.
553 (void)srn_fiber_spawn(ctx, fiber_dwake_consumer_entry, nullptr);
554 (void)srn_fiber_spawn(ctx, fiber_dwake_producer_entry, nullptr);
555
556 srn_sched_run(sched, 1);
557
559
560 RELEASE_CONTEXT(ctx);
561 SHUTDOWN_ENGINE(mm, engine);
562}
#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 672 of file fiber_tests.h.

672 {
673 MAKE_ENGINE(mm, engine);
674 MAKE_CONTEXT(engine, ctx);
675 srn_scheduler_t *sched = engine->scheduler;
676 ASSERT_NOT_NULL(sched);
677
678 atomic_store(&fiber_mt_counter, 0);
679 enum { N = 256 };
680 for (int i = 0; i < N; i++) {
681 (void)srn_fiber_spawn(ctx, fiber_mt_entry, nullptr);
682 }
683
684 srn_sched_run(sched, 4);
685
686 TEST_CHECK(atomic_load(&fiber_mt_counter) == N);
687
688 RELEASE_CONTEXT(ctx);
689 SHUTDOWN_ENGINE(mm, engine);
690}
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 708 of file fiber_tests.h.

708 {
709 MAKE_ENGINE(mm, engine);
710 MAKE_CONTEXT(engine, ctx);
711 srn_scheduler_t *sched = engine->scheduler;
712 ASSERT_NOT_NULL(sched);
713
714 atomic_store(&fiber_mt_yield_counter, 0);
715 enum { N = 64, ROUNDS = 8 };
716 for (int i = 0; i < N; i++) {
717 (void)srn_fiber_spawn(ctx, fiber_mt_yield_entry, (void *)(intptr_t)ROUNDS);
718 }
719
720 srn_sched_run(sched, 4);
721
722 TEST_CHECK(atomic_load(&fiber_mt_yield_counter) == N * ROUNDS);
723
724 RELEASE_CONTEXT(ctx);
725 SHUTDOWN_ENGINE(mm, engine);
726}
#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 444 of file fiber_tests.h.

444 {
445 MAKE_ENGINE(mm, engine);
446 MAKE_CONTEXT(engine, ctx);
447 srn_scheduler_t *sched = engine->scheduler;
448 ASSERT_NOT_NULL(sched);
449
451 fiber_mbox.value = 7;
452 fiber_mbox.has_value = true; // value present before the consumer runs
453 fiber_mbox_got = 0;
454
455 (void)srn_fiber_spawn(ctx, fiber_consumer_entry, nullptr);
456
457 srn_sched_run(sched, 1);
458
460 TEST_CHECK(fiber_mbox.waiter == nullptr); // never registered as a waiter
461
462 RELEASE_CONTEXT(ctx);
463 SHUTDOWN_ENGINE(mm, engine);
464}
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 484 of file fiber_tests.h.

484 {
485 MAKE_ENGINE(mm, engine);
486 MAKE_CONTEXT(engine, ctx);
487 srn_scheduler_t *sched = engine->scheduler;
488 ASSERT_NOT_NULL(sched);
489
490 srn_fiber_t *stuck = srn_fiber_spawn(ctx, fiber_stuck_entry, nullptr);
491 ASSERT_NOT_NULL(stuck);
492
493 // Drains the ready queue. The stuck fiber suspends and is abandoned.
494 srn_sched_run(sched, 1);
496
497 // The registry lets shutdown find and free the abandoned fiber's stack.
498 srn_sched_shutdown(sched);
499
500 RELEASE_CONTEXT(ctx);
501 SHUTDOWN_ENGINE(mm, engine);
502}
@ SRN_FIBER_SUSPENDED
Parked off the run queue, awaits srn_fiber_ready.
Definition fiber.h:238
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 256 of file fiber_tests.h.

256 {
257 MAKE_ENGINE(mm, engine);
258 MAKE_CONTEXT(engine, ctx);
259 srn_scheduler_t *sched = engine->scheduler;
260 ASSERT_NOT_NULL(sched);
261
263 enum { N = 4 };
264 srn_fiber_t *fibers[N];
265 for (int i = 0; i < N; i++) {
266 fibers[i] = srn_fiber_spawn(ctx, fiber_run_entry, nullptr);
267 ASSERT_NOT_NULL(fibers[i]);
268 }
269
270 srn_sched_run(sched, 1);
271
273 for (int i = 0; i < N; i++) {
274 // The struct lives in the context block after reaping. Only the stack is
275 // released, so state and result are still readable here.
276 TEST_CHECK(fibers[i]->state == SRN_FIBER_DONE);
277 TEST_CHECK(fibers[i]->result == &fiber_ok_value);
278 }
279
280 RELEASE_CONTEXT(ctx);
281 SHUTDOWN_ENGINE(mm, engine);
282}
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 757 of file fiber_tests.h.

757 {
758 MAKE_ENGINE(mm, engine);
759 MAKE_CONTEXT(engine, ctx);
760 srn_scheduler_t *sched = engine->scheduler;
761 ASSERT_NOT_NULL(sched);
762
763 atomic_store(&fiber_stop_rounds, 0);
764 // Stopper first so it reaches the single worker before the pending fibers.
765 (void)srn_fiber_spawn(ctx, fiber_stopper_entry, sched);
766 enum { PENDING = 3 };
767 for (int i = 0; i < PENDING; i++) {
768 (void)srn_fiber_spawn(ctx, fiber_pending_entry, nullptr);
769 }
770
771 // Returns when the stopper calls srn_sched_stop, with the pending fibers
772 // still queued.
773 srn_sched_run(sched, 1);
774
775 // Only the stopper ran (three rounds); no pending fiber ran.
776 TEST_CHECK(atomic_load(&fiber_stop_rounds) == 3);
777
778 // Reap the pending fibers while their structs (in the context block) are
779 // still alive, before releasing the context. SHUTDOWN_ENGINE calls shutdown
780 // again, which is a no-op on an already torn-down scheduler.
781 srn_sched_shutdown(sched);
782
783 RELEASE_CONTEXT(ctx);
784 SHUTDOWN_ENGINE(mm, engine);
785}
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 419 of file fiber_tests.h.

419 {
420 MAKE_ENGINE(mm, engine);
421 MAKE_CONTEXT(engine, ctx);
422 srn_scheduler_t *sched = engine->scheduler;
423 ASSERT_NOT_NULL(sched);
424
426 fiber_mbox_got = 0;
427
428 // Order matters, the consumer must be enqueued first so it runs and suspends
429 // before the producer fills the slot.
430 (void)srn_fiber_spawn(ctx, fiber_consumer_entry, nullptr);
431 (void)srn_fiber_spawn(ctx, fiber_producer_entry, nullptr);
432
433 srn_sched_run(sched, 1);
434
436
437 RELEASE_CONTEXT(ctx);
438 SHUTDOWN_ENGINE(mm, engine);
439}
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 584 of file fiber_tests.h.

584 {
585 MAKE_ENGINE(mm, engine);
586 MAKE_CONTEXT(engine, ctx);
587 srn_scheduler_t *sched = engine->scheduler;
588 ASSERT_NOT_NULL(sched);
589
590 fiber_wf_seen = nullptr;
591 // Waiter made first, so it runs and parks before the target finishes.
592 (void)srn_fiber_spawn(ctx, fiber_wf_waiter_entry, nullptr);
594
595 srn_sched_run(sched, 1);
596
598
599 RELEASE_CONTEXT(ctx);
600 SHUTDOWN_ENGINE(mm, engine);
601}
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 605 of file fiber_tests.h.

605 {
606 MAKE_ENGINE(mm, engine);
607 MAKE_CONTEXT(engine, ctx);
608 srn_scheduler_t *sched = engine->scheduler;
609 ASSERT_NOT_NULL(sched);
610
611 fiber_wf_seen = nullptr;
612 // Target made first, so it runs and finishes before the waiter runs.
614 (void)srn_fiber_spawn(ctx, fiber_wf_waiter_entry, nullptr);
615
616 srn_sched_run(sched, 1);
617
619
620 RELEASE_CONTEXT(ctx);
621 SHUTDOWN_ENGINE(mm, engine);
622}
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 637 of file fiber_tests.h.

637 {
638 MAKE_ENGINE(mm, engine);
639 MAKE_CONTEXT(engine, ctx);
640 srn_scheduler_t *sched = engine->scheduler;
641 ASSERT_NOT_NULL(sched);
642
643 fiber_wf_woke = 0;
644 // Three waiters made first so they all park, then the target finishes.
645 (void)srn_fiber_spawn(ctx, fiber_wf_counting_waiter, nullptr);
646 (void)srn_fiber_spawn(ctx, fiber_wf_counting_waiter, nullptr);
647 (void)srn_fiber_spawn(ctx, fiber_wf_counting_waiter, nullptr);
649
650 srn_sched_run(sched, 1);
651
653
654 RELEASE_CONTEXT(ctx);
655 SHUTDOWN_ENGINE(mm, engine);
656}
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 301 of file fiber_tests.h.

301 {
302 MAKE_ENGINE(mm, engine);
303 MAKE_CONTEXT(engine, ctx);
304 srn_scheduler_t *sched = engine->scheduler;
305 ASSERT_NOT_NULL(sched);
306
307 fiber_yield_n = 0;
308 (void)srn_fiber_spawn(ctx, fiber_yield_entry, (void *)(intptr_t)1);
309 (void)srn_fiber_spawn(ctx, fiber_yield_entry, (void *)(intptr_t)2);
310
311 srn_sched_run(sched, 1);
312
314 int ones = 0;
315 int twos = 0;
316 for (int i = 0; i < 4; i++) {
317 if (fiber_yield_log[i] == 1) {
318 ones++;
319 } else if (fiber_yield_log[i] == 2) {
320 twos++;
321 }
322 }
323 TEST_CHECK(ones == 2);
324 TEST_CHECK(twos == 2);
325
326 RELEASE_CONTEXT(ctx);
327 SHUTDOWN_ENGINE(mm, engine);
328}
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 348 of file fiber_tests.h.

348 {
349 MAKE_ENGINE(mm, engine);
350 MAKE_CONTEXT(engine, ctx);
351 srn_scheduler_t *sched = engine->scheduler;
352 ASSERT_NOT_NULL(sched);
353
354 fiber_rr_n = 0;
355 (void)srn_fiber_spawn(ctx, fiber_rr_entry, (void *)(intptr_t)1);
356 (void)srn_fiber_spawn(ctx, fiber_rr_entry, (void *)(intptr_t)2);
357
358 srn_sched_run(sched, 1);
359
361 // Strict alternation, a yielding fiber never runs two steps back to back
362 // while a peer is ready.
363 for (int i = 1; i < 6; i++) {
365 TEST_MSG(
366 "order: %d %d %d %d %d %d", fiber_rr_log[0], fiber_rr_log[1], fiber_rr_log[2],
368 );
369 }
370
371 RELEASE_CONTEXT(ctx);
372 SHUTDOWN_ENGINE(mm, engine);
373}
#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 141 of file fiber_tests.h.

141 {
142 MAKE_ENGINE(mm, engine);
143 MAKE_CONTEXT(engine, ctx);
144 srn_scheduler_t *sched = engine->scheduler;
145
146 spawn_copy_seen = 0;
147 {
148 spawn_copy_args_t args = {.value = 4242};
150 }
151
152 srn_sched_run(sched, 1);
154
155 RELEASE_CONTEXT(ctx);
156 SHUTDOWN_ENGINE(mm, engine);
157}
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:461
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 174 of file fiber_tests.h.

174 {
175 size_t page = srn_mm_get_os_page_size();
176
178
179 TEST_CHECK(s.guard != nullptr);
180 TEST_CHECK(s.limit != nullptr);
181 TEST_CHECK(s.start != nullptr);
182 // The guard sits exactly one page below the usable region.
183 TEST_CHECK((char *)s.limit == (char *)s.guard + page);
184 // The usable region is non-empty, page-aligned, and at least the default.
185 TEST_CHECK((char *)s.start > (char *)s.limit);
186 TEST_CHECK(((uintptr_t)s.limit & (page - 1)) == 0);
188
189 // The whole usable region is writable end to end. The guard is left alone.
190 ((char *)s.limit)[0] = (char)0x5A;
191 ((char *)s.start)[-1] = (char)0x5A;
192
194}
size_t srn_mm_get_os_page_size(void)
Retutrns the OS page size.
Definition default.c:303
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:611
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:180
One stack per fiber, mapped with a guard page at the low end so an overflow faults deterministically ...
Definition fiber.h:218
void * guard
The protected page to detect stack overflows.
Definition fiber.h:224
void * limit
Low end of usable region.
Definition fiber.h:222
void * start
High end, stack pointer initialises to this address.
Definition fiber.h:220
Here is the call graph for this function:

◆ test_fiber_switch()

void test_fiber_switch ( )
static

Definition at line 216 of file fiber_tests.h.

216 {
218
220
222 fiber_pp_worker.stack = worker_stack;
224 srn_fiber_ctx_make(&fiber_pp_worker.fiber_ctx, worker_stack, fiber_pp_entry, nullptr);
225
226 fiber_pp_ticks = 0;
227 fiber_pp_rounds = 5;
228
229 // `rounds` yields, plus one more switch to let the worker run to completion.
230 for (int i = 0; i <= fiber_pp_rounds; i++) {
232 }
233
236
237 srn_fiber_stack_free(worker_stack);
238}
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:154
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:236
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 54 of file fiber_tests.h.

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

◆ test_fiber_types()

void test_fiber_types ( )
static

Definition at line 159 of file fiber_tests.h.

159 {
160 // Smoke test, the public types exist and the build/test wiring works.
161 // The saved context is a single stack-pointer word.
162 TEST_CHECK(sizeof(srn_fiber_ctx_t) == sizeof(void *));
163 // The lifecycle states run from creation to completion in order.
169}
@ SRN_FIBER_READY
On the run queue, eligible to run.
Definition fiber.h:234
The saved context of a suspended fiber is a single word, its stack pointer at the moment it was switc...
Definition fiber.h:198

Variable Documentation

◆ fiber_dwake_runs

int fiber_dwake_runs
static

Definition at line 510 of file fiber_tests.h.

◆ fiber_dwake_signalled

bool fiber_dwake_signalled
static

Definition at line 509 of file fiber_tests.h.

◆ fiber_dwake_waiter

srn_fiber_t* fiber_dwake_waiter
static

Definition at line 508 of file fiber_tests.h.

◆ fiber_mbox

fiber_mbox_t fiber_mbox
static

Definition at line 384 of file fiber_tests.h.

◆ fiber_mbox_got

int fiber_mbox_got
static

Definition at line 385 of file fiber_tests.h.

◆ fiber_mt_counter

atomic_int fiber_mt_counter
static

Definition at line 663 of file fiber_tests.h.

◆ fiber_mt_yield_counter

atomic_int fiber_mt_yield_counter
static

Definition at line 696 of file fiber_tests.h.

◆ fiber_ok_value

int fiber_ok_value
static

Definition at line 242 of file fiber_tests.h.

◆ fiber_pp_rounds

int fiber_pp_rounds
static

Definition at line 204 of file fiber_tests.h.

◆ fiber_pp_thread

srn_fiber_t fiber_pp_thread
static

Definition at line 201 of file fiber_tests.h.

◆ fiber_pp_ticks

int fiber_pp_ticks
static

Definition at line 203 of file fiber_tests.h.

◆ fiber_pp_worker

srn_fiber_t fiber_pp_worker
static

Definition at line 202 of file fiber_tests.h.

◆ fiber_rr_log

int fiber_rr_log[6]
static

Definition at line 333 of file fiber_tests.h.

◆ fiber_rr_n

int fiber_rr_n
static

Definition at line 334 of file fiber_tests.h.

◆ fiber_run_counter

int fiber_run_counter
static

Definition at line 247 of file fiber_tests.h.

◆ fiber_stop_rounds

atomic_int fiber_stop_rounds
static

Definition at line 734 of file fiber_tests.h.

◆ fiber_wf_result

int fiber_wf_result
static

Definition at line 567 of file fiber_tests.h.

◆ fiber_wf_seen

srn_fiber_result_t fiber_wf_seen
static

Definition at line 569 of file fiber_tests.h.

◆ fiber_wf_target

srn_fiber_t* fiber_wf_target
static

Definition at line 568 of file fiber_tests.h.

◆ fiber_wf_woke

int fiber_wf_woke
static

Definition at line 626 of file fiber_tests.h.

◆ fiber_yield_log

int fiber_yield_log[4]
static

Definition at line 288 of file fiber_tests.h.

◆ fiber_yield_n

int fiber_yield_n
static

Definition at line 289 of file fiber_tests.h.

◆ spawn_copy_seen

int spawn_copy_seen
static

Definition at line 130 of file fiber_tests.h.