Serene Runtime 1.0.0-dev
C runtime for the Serene programming language
Loading...
Searching...
No Matches
configuration.h
Go to the documentation of this file.
1/* -*- C -*-
2 * Serene programming language
3 * Copyright (C) 2019-2026 Sameer Rahmani <lxsameer@lxsameer.com>
4 *
5 * This library is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19/** @file
20 The single place that holds every runtime knob.
21
22 `srn_configuration_t` gathers the tunable values the runtime offers into one
23 struct, grouped by subsystem (memory manager, fibers, reactor, limits). Code
24 that needs a configurable value reads it from here rather than from a scattered
25 `#define`, so there is one source of truth and one place to override.
26
27 What lives here is policy: values that could reasonably differ between runs.
28 What does NOT live here is structure or protocol -- types, memory-layout
29 constants, and constants that size fixed C arrays or feed a `static_assert`
30 (the seq branching factor, the value payload size, reserved id ranges). Those
31 stay compile-time macros because the code cannot express them as a runtime
32 field without being restructured.
33
34 The configuration is read-only once the runtime is up, and it must exist before
35 the memory manager is created (the MM needs `mm.block_size_magnitude` at
36 init), so it is
37 the first thing constructed.
38*/
39
40#pragma once
41
42#include <stddef.h>
43
44// -----------------------------------------------------------------------------
45// Defaults
46// -----------------------------------------------------------------------------
47// One source for every default. `SRN_CONFIG_DEFAULTS` below builds a fully
48// populated configuration from these.
49
50/**
51 * Magnitude of one memory-manager block. The block size is
52 * `1 << block_size_magnitude` bytes, so 17 is 128 KiB.
53 */
54#define SRN_CONFIG_DEFAULT_BLOCK_SIZE_MAGNITUDE 17U
55
56/**
57 * The default block size in bytes, derived from the magnitude.
58 */
59#define SRN_CONFIG_DEFAULT_BLOCK_SIZE ((size_t)1 << SRN_CONFIG_DEFAULT_BLOCK_SIZE_MAGNITUDE)
60
61/**
62 * Size of every fiber stack, in bytes. All fiber stacks share one size.
63 */
64#define SRN_CONFIG_DEFAULT_FIBER_STACK_SIZE ((size_t)1024 * 1024 * 8)
65
66/**
67 * Pages in the guard band below every fiber stack. A band wider than one page
68 * shrinks the chance that a single oversized frame in code compiled without
69 * stack probing steps over the guard and corrupts a neighbouring stack. The
70 * whole band is PROT_NONE and never faulted in.
71 */
72#define SRN_CONFIG_DEFAULT_FIBER_GUARD_PAGES ((size_t)16)
73
74/**
75 * Worker count a run uses when the caller does not specify one. Zero
76 * delegates to the machine, one worker per CPU the process may run on,
77 * resolved at run time by srn_thread_cpu_count.
78 */
79#define SRN_CONFIG_DEFAULT_WORKERS 0U
80
81/**
82 * Upper bound a requested worker count is clamped to.
83 */
84#define SRN_CONFIG_DEFAULT_MAX_WORKERS 256U
85
86/**
87 * The absolute worker ceiling. `fiber.max_workers` may not exceed it, and
88 * the scheduler clamps every run to it regardless of the configuration.
89 */
90#define SRN_MAX_WORKERS 256U
91
92/**
93 * Magnitude of each reactor channel's SQ/CQ rings, capacity is `1 << magnitude`
94 * slots, which also bounds a channel's in-flight operations.
95 */
96#define SRN_CONFIG_DEFAULT_REACTOR_RING_MAGNITUDE 8U
97
98/**
99 * Most completions a worker drains from a channel in one pass.
100 */
101#define SRN_CONFIG_DEFAULT_REACTOR_REAP_BATCH 64U
102
103/**
104 * Largest string the runtime accepts, in bytes.
105 */
106#define SRN_CONFIG_DEFAULT_STRING_MAX_LEN ((size_t)1U << 20U)
107
108/**
109 * Longest namespace name the runtime accepts, in bytes.
110 */
111#define SRN_CONFIG_DEFAULT_NS_NAME_MAX_LEN 4096U
112
113/**
114 * Deepest value nesting the recursive value protocols accept.
115 */
116#define SRN_CONFIG_DEFAULT_MAX_VALUE_DEPTH 512U
117
118// -----------------------------------------------------------------------------
119// Memory-manager knobs
120// -----------------------------------------------------------------------------
121typedef struct srn_mm_config_t {
122 /// Magnitude of one block the arena hands out from. The block size is
123 /// `1 << block_size_magnitude` bytes, a power of two by construction, so
124 /// it is a whole number of pages on every platform whose page size it
125 /// covers. Read at MM init.
128
129// -----------------------------------------------------------------------------
130// Fiber and scheduler knobs
131// -----------------------------------------------------------------------------
132typedef struct srn_fiber_config_t {
133 /// Size of every fiber stack, in bytes. A per-fiber size of 0 falls back to
134 /// this.
136
137 /// Pages in the guard band below every fiber stack. Applies to every stack
138 /// the run allocates. Must be at least one page. Read at stack allocation.
140
141 /// Worker count used when a run does not specify one. Zero delegates to
142 /// the CPU count at run time.
143 size_t workers;
144
145 /// Hard ceiling a requested worker count is clamped to.
148
149// -----------------------------------------------------------------------------
150// Reactor knobs
151// -----------------------------------------------------------------------------
158
159typedef struct srn_reactor_config_t {
160 /// Magnitude of each channel's SQ/CQ rings, capacity is `1 << magnitude`.
161 /// This also bounds the operations a channel can have in flight, so the
162 /// armed-operation table is sized from it rather than grown.
164
165 /// Most completions a worker drains from its channel in a single pass.
167 /// What IO backend to use
170
171/**
172 * Size and length limits the runtime enforces.
173 */
174typedef struct srn_limits_config_t {
175 /// Largest string accepted, in bytes.
177
178 /// Longest namespace name accepted, in bytes.
180
181 // TODO: Enforce this limit. Print, eq, and hash recurse one C stack frame
182 // per nesting level, so a deep value overflows a fixed size fiber stack.
183 // Thread a countdown through the three walks, print elides deeper
184 // structure, eq and hash report a resource error. An iterative rewrite
185 // with heap worklists removes the limit entirely and is the long term
186 // shape.
187 /// Deepest value nesting print, eq, and hash accept.
190
191// -----------------------------------------------------------------------------
192// The configuration
193// -----------------------------------------------------------------------------
194
195/**
196 * Every runtime knob, in one place. Constructed before the memory manager and
197 * read-only thereafter.
198 */
205
206#ifdef __linux__
207# define SRN_CHOOSE_BACKEND SRN_REACTOR_EPOLL
208#endif
209
210#ifdef __APPLE__
211# define SRN_CHOOSE_BACKEND SRN_REACTOR_KQUEUE
212#endif
213
214#ifdef _WIN32
215# define SRN_CHOOSE_BACKEND SRN_REACTOR_IOCP
216#endif
217
218#ifndef SRN_CHOOSE_BACKEND
219# error "no reactor backend for this target (need epoll/kqueue/IOCP/...)"
220#endif
221
222/**
223 * A configuration with every field set to its default. Use as an initializer:
224 * `srn_configuration_t cfg = SRN_CONFIG_DEFAULTS;`.
225 */
226
227/**
228 * Panic unless every knob in `config` is usable. Called by `srn_mm_init` and
229 * `srn_engine_make` on the configuration they are given, so a bad value
230 * fails loudly at startup, naming the knob, instead of corrupting whatever
231 * is sized or bounded by it later.
232 */
233[[gnu::nonnull(1)]]
234void srn_config_validate(const srn_configuration_t *config);
235
236#define SRN_CONFIG_DEFAULTS \
237 ((srn_configuration_t){ \
238 .mm = {.block_size_magnitude = SRN_CONFIG_DEFAULT_BLOCK_SIZE_MAGNITUDE}, \
239 .fiber = \
240 {.stack_size = SRN_CONFIG_DEFAULT_FIBER_STACK_SIZE, \
241 .guard_pages = SRN_CONFIG_DEFAULT_FIBER_GUARD_PAGES, \
242 .workers = SRN_CONFIG_DEFAULT_WORKERS, \
243 .max_workers = SRN_CONFIG_DEFAULT_MAX_WORKERS}, \
244 .reactor = \
245 { \
246 .ring_magnitude = SRN_CONFIG_DEFAULT_REACTOR_RING_MAGNITUDE, \
247 .reap_batch = SRN_CONFIG_DEFAULT_REACTOR_REAP_BATCH, \
248 .backend = SRN_CHOOSE_BACKEND, \
249 }, \
250 .limits = { \
251 .string_max_len = SRN_CONFIG_DEFAULT_STRING_MAX_LEN, \
252 .ns_name_max_len = SRN_CONFIG_DEFAULT_NS_NAME_MAX_LEN, \
253 .max_value_depth = SRN_CONFIG_DEFAULT_MAX_VALUE_DEPTH \
254 } \
255 })
srn_reactor_backend_e
@ SRN_REACTOR_KQUEUE
@ SRN_REACTOR_IO_URING
@ SRN_REACTOR_IOCP
@ SRN_REACTOR_EPOLL
void srn_config_validate(const srn_configuration_t *config)
A configuration with every field set to its default.
Every runtime knob, in one place.
srn_reactor_config_t reactor
srn_fiber_config_t fiber
srn_limits_config_t limits
srn_mm_config_t mm
size_t workers
Worker count used when a run does not specify one.
size_t guard_pages
Pages in the guard band below every fiber stack.
size_t max_workers
Hard ceiling a requested worker count is clamped to.
size_t stack_size
Size of every fiber stack, in bytes.
Size and length limits the runtime enforces.
size_t max_value_depth
Deepest value nesting print, eq, and hash accept.
size_t ns_name_max_len
Longest namespace name accepted, in bytes.
size_t string_max_len
Largest string accepted, in bytes.
size_t block_size_magnitude
Magnitude of one block the arena hands out from.
size_t reap_batch
Most completions a worker drains from its channel in a single pass.
size_t ring_magnitude
Magnitude of each channel's SQ/CQ rings, capacity is 1 << magnitude.
srn_reactor_backend_e backend
What IO backend to use.