Serene Runtime 1.0.0
C runtime for the Serene programming language
Loading...
Searching...
No Matches
06_request_term.c
Go to the documentation of this file.
1/* -*- C -*-
2 * Serene programming language
3 * Copyright (C) 2019-2026 Sameer Rahmani <[email protected]>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19// Example 06 -- asking the scheduler to stop.
20//
21// A scheduler normally runs until it goes quiescent, every worker idle with no
22// work left. `srn_sched_stop` stops it before that point. Each worker
23// notices the request at the top of its loop and stops once the fiber it is
24// running yields or finishes, so a fiber is never cut off mid step. Work still
25// queued is left unrun, and its stacks are reclaimed at shutdown through the
26// scheduler's registry. The call is safe from any thread, which is what makes
27// it usable from a signal handler reacting to Ctrl-C or SIGTERM.
28//
29// A controller fiber runs first and requests termination, then returns
30// normally. It is the slice in flight, and termination lets it finish cleanly.
31// A batch of task fibers sit queued behind it. Because the controller stops the
32// scheduler before they get a turn, they never run, and the final count of
33// tasks that ran is zero. That is the point: a requested stop abandons queued
34// work rather than draining it.
35
36#include <stdatomic.h>
37#include <stdio.h>
38
39#include <serene/runtime.h>
40
41static int ok;
42
43#define TASK_COUNT 16
44
45static atomic_int tasks_ran;
46
47static srn_fiber_result_t task(srn_context_t *ctx, void *arg) {
48 (void)ctx;
49 (void)arg;
50 atomic_fetch_add(&tasks_ran, 1);
51 return &ok;
52}
53
55 (void)ctx;
56 // The scheduler arrives through the argument, so the controller can act on
57 // it.
58 srn_scheduler_t *sched = arg;
59 printf("controller: stopping the scheduler before the tasks run\n");
60 srn_sched_stop(sched);
61 // Returning normally is the clean boundary the worker stops on.
62 return &ok;
63}
64
65int main(void) {
66 srn_mm_t *mm = srn_mm_init();
67 srn_engine_t *engine = srn_engine_make(mm);
68 srn_context_t *ctx = srn_context_make(engine);
69 srn_scheduler_t *sched = engine->scheduler;
70
71 atomic_store(&tasks_ran, 0);
72
73 // The controller is created first so it reaches the front of the ready queue
74 // first and requests the stop before any task is dequeued.
75 (void)srn_fiber_make(ctx, sched, controller, sched, 0);
76 for (int i = 0; i < TASK_COUNT; i++) {
77 (void)srn_fiber_make(ctx, sched, task, nullptr, 0);
78 }
79
80 // One worker keeps the order deterministic: the controller runs, stops the
81 // scheduler, and the worker exits at the top of its next loop with the tasks
82 // still queued.
83 srn_sched_run(sched, 1);
84
85 int ran = atomic_load(&tasks_ran);
86 printf("%d of %d tasks ran before termination\n", ran, TASK_COUNT);
87 printf("the rest were left queued and are reclaimed at shutdown\n");
88
89 // Teardown order matters once a run stops with work still queued. The unrun
90 // tasks are still on the scheduler's registry, yet their fiber structs live
91 // in this context's blocks. srn_engine_shutdown reaps the scheduler, walking
92 // that registry, so it has to run before the context that owns those structs
93 // is released. The examples that drain every fiber leave an empty registry,
94 // so the order does not matter for them.
95 srn_engine_shutdown(engine);
98 return 0;
99}
static int ok
Definition 01_hello.c:36
static srn_fiber_result_t controller(srn_context_t *ctx, void *arg)
static srn_fiber_result_t task(srn_context_t *ctx, void *arg)
int main(void)
#define TASK_COUNT
static atomic_int tasks_ran
srn_context_t * srn_context_make(srn_engine_t *engine)
Make an empty context, by allocating a new memory block.
Definition context.c:38
int srn_context_release(srn_context_t *ctx)
Definition context.c:63
srn_mm_t * srn_mm_init()
Initialize the memory manager, this function will panic on error.
Definition default.c:294
void srn_mm_shutdown(srn_mm_t *mm)
Shut down the memory manager and release the resources.
Definition default.c:325
srn_engine_t * srn_engine_make(srn_mm_t *mm)
Definition engine.c:92
void srn_engine_shutdown(srn_engine_t *engine)
Definition engine.c:123
srn_fiber_t * srn_fiber_make(srn_context_t *ctx, srn_scheduler_t *sched, srn_fiber_entry_t entry, void *arg, size_t stack_size)
Create a fiber that will run entry(ctx, arg).
Definition fiber.c:169
void * srn_fiber_result_t
Definition fiber.h:117
void srn_sched_stop(srn_scheduler_t *sched)
Ask a running scheduler to stop.
Definition scheduler.c:849
void srn_sched_run(srn_scheduler_t *sched, int nworkers)
Run the scheduler with nworkers os threads draining it, returning once the pool goes quiescent (every...
Definition scheduler.c:784
Engine is a structure to own the long living and main pieces of the compiler.
Definition engine.h:49
srn_scheduler_t * scheduler
The fiber scheduler, set by srn_sched_init.
Definition engine.h:67
Main memory manager structure that will own all the allocated blocks and data.
Definition interface.h:112