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 <[email protected]>
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)128 * 1024)
65
66/**
67 * Worker count a run uses when the caller does not specify one. Zero
68 * delegates to the machine, one worker per CPU the process may run on,
69 * resolved at run time by srn_thread_cpu_count.
70 */
71#define SRN_CONFIG_DEFAULT_WORKERS 0U
72
73/**
74 * Upper bound a requested worker count is clamped to.
75 */
76#define SRN_CONFIG_DEFAULT_MAX_WORKERS 256U
77
78/**
79 * The absolute worker ceiling. `fiber.max_workers` may not exceed it, and
80 * the scheduler clamps every run to it regardless of the configuration.
81 */
82#define SRN_MAX_WORKERS 256U
83
84/**
85 * Magnitude of each reactor channel's SQ/CQ rings, capacity is `1 << magnitude`
86 * slots, which also bounds a channel's in-flight operations.
87 */
88#define SRN_CONFIG_DEFAULT_REACTOR_RING_MAGNITUDE 8U
89
90/**
91 * Most completions a worker drains from a channel in one pass.
92 */
93#define SRN_CONFIG_DEFAULT_REACTOR_REAP_BATCH 64U
94
95/**
96 * Largest string the runtime accepts, in bytes.
97 */
98#define SRN_CONFIG_DEFAULT_STRING_MAX_LEN ((size_t)1U << 20U)
99
100/**
101 * Longest namespace name the runtime accepts, in bytes.
102 */
103#define SRN_CONFIG_DEFAULT_NS_NAME_MAX_LEN 4096U
104
105/**
106 * Deepest value nesting the recursive value protocols accept.
107 */
108#define SRN_CONFIG_DEFAULT_MAX_VALUE_DEPTH 512U
109
110// -----------------------------------------------------------------------------
111// Memory-manager knobs
112// -----------------------------------------------------------------------------
113typedef struct srn_mm_config_t {
114 /// Magnitude of one block the arena hands out from. The block size is
115 /// `1 << block_size_magnitude` bytes, a power of two by construction, so
116 /// it is a whole number of pages on every platform whose page size it
117 /// covers. Read at MM init.
120
121// -----------------------------------------------------------------------------
122// Fiber and scheduler knobs
123// -----------------------------------------------------------------------------
124typedef struct srn_fiber_config_t {
125 /// Size of every fiber stack, in bytes. A per-fiber size of 0 falls back to
126 /// this.
128
129 /// Worker count used when a run does not specify one. Zero delegates to
130 /// the CPU count at run time.
131 size_t workers;
132
133 /// Hard ceiling a requested worker count is clamped to.
136
137// -----------------------------------------------------------------------------
138// Reactor knobs
139// -----------------------------------------------------------------------------
146
147typedef struct srn_reactor_config_t {
148 /// Magnitude of each channel's SQ/CQ rings, capacity is `1 << magnitude`.
149 /// This also bounds the operations a channel can have in flight, so the
150 /// armed-operation table is sized from it rather than grown.
152
153 /// Most completions a worker drains from its channel in a single pass.
155 /// What IO backend to use
158
159/**
160 * Size and length limits the runtime enforces.
161 */
162typedef struct srn_limits_config_t {
163 /// Largest string accepted, in bytes.
165
166 /// Longest namespace name accepted, in bytes.
168
169 // TODO: Enforce this limit. Print, eq, and hash recurse one C stack frame
170 // per nesting level, so a deep value overflows a fixed size fiber stack.
171 // Thread a countdown through the three walks, print elides deeper
172 // structure, eq and hash report a resource error. An iterative rewrite
173 // with heap worklists removes the limit entirely and is the long term
174 // shape.
175 /// Deepest value nesting print, eq, and hash accept.
178
179// -----------------------------------------------------------------------------
180// The configuration
181// -----------------------------------------------------------------------------
182
183/**
184 * Every runtime knob, in one place. Constructed before the memory manager and
185 * read-only thereafter.
186 */
193
194#ifdef __linux__
195# define SRN_CHOOSE_BACKEND SRN_REACTOR_EPOLL
196#endif
197
198#ifdef __APPLE__
199# define SRN_CHOOSE_BACKEND SRN_REACTOR_KQUEUE
200#endif
201
202#ifdef _WIN32
203# define SRN_CHOOSE_BACKEND SRN_REACTOR_IOCP
204#endif
205
206#ifndef SRN_CHOOSE_BACKEND
207# error "no reactor backend for this target (need epoll/kqueue/IOCP/...)"
208#endif
209
210/**
211 * A configuration with every field set to its default. Use as an initializer:
212 * `srn_configuration_t cfg = SRN_CONFIG_DEFAULTS;`.
213 */
214
215/**
216 * Panic unless every knob in `config` is usable. Called by `srn_mm_init` and
217 * `srn_engine_make` on the configuration they are given, so a bad value
218 * fails loudly at startup, naming the knob, instead of corrupting whatever
219 * is sized or bounded by it later.
220 */
221[[gnu::nonnull(1)]]
222void srn_config_validate(const srn_configuration_t *config);
223
224#define SRN_CONFIG_DEFAULTS \
225 ((srn_configuration_t){ \
226 .mm = {.block_size_magnitude = SRN_CONFIG_DEFAULT_BLOCK_SIZE_MAGNITUDE}, \
227 .fiber = \
228 {.stack_size = SRN_CONFIG_DEFAULT_FIBER_STACK_SIZE, \
229 .workers = SRN_CONFIG_DEFAULT_WORKERS, \
230 .max_workers = SRN_CONFIG_DEFAULT_MAX_WORKERS}, \
231 .reactor = \
232 { \
233 .ring_magnitude = SRN_CONFIG_DEFAULT_REACTOR_RING_MAGNITUDE, \
234 .reap_batch = SRN_CONFIG_DEFAULT_REACTOR_REAP_BATCH, \
235 .backend = SRN_CHOOSE_BACKEND, \
236 }, \
237 .limits = { \
238 .string_max_len = SRN_CONFIG_DEFAULT_STRING_MAX_LEN, \
239 .ns_name_max_len = SRN_CONFIG_DEFAULT_NS_NAME_MAX_LEN, \
240 .max_value_depth = SRN_CONFIG_DEFAULT_MAX_VALUE_DEPTH \
241 } \
242 })
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 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.