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