MMgr v1.0.0
Zero-heap memory manager in C11. One borrowed buffer, carved by asserted offset.
Loading...
Searching...
No Matches
mmgr_config.h
1/**
2 * @brief Build-time settings: widths, region sizes, feature switches and the region carving macros.
3 *
4 * @note Each tunable sits behind #ifndef, which lets a build set it first; MMGR_SWAR_BITS is the exception.
5 */
6#ifndef MMGR_CONFIG_H
7#define MMGR_CONFIG_H
8
9#include <stdint.h>
10
11#include "config/mmgr_compiler_directives.h"
12
13/**
14 * @brief Width in bits of mmgr_word, the register every SWAR lane operation runs in.
15 *
16 * @note Derived from UINTPTR_MAX as 64, 32 or 16 when the build does not set it.
17 * @warning A target whose UINTPTR_MAX matches none of the three raises #error; pass -DMMGR_WORD_BITS.
18 */
19#ifndef MMGR_WORD_BITS
20#if UINTPTR_MAX == 0xFFFFFFFFFFFFFFFFu
21#define MMGR_WORD_BITS 64
22#elif UINTPTR_MAX == 0xFFFFFFFFu
23#define MMGR_WORD_BITS 32
24#elif UINTPTR_MAX == 0xFFFFu
25#define MMGR_WORD_BITS 16
26#else
27#error "cannot derive MMGR_WORD_BITS from UINTPTR_MAX on this target - pass -DMMGR_WORD_BITS=16|32|64"
28#endif
29#endif
30
31/**
32 * @brief Width in bits of mmgr_idx, the type every offset and length is carried in.
33 *
34 * @note Follows MMGR_WORD_BITS below 32, and is capped at 32 above that.
35 * @warning mmgr_types.h accepts only 16 or 32, and asserts mmgr_idx fits inside mmgr_word.
36 */
37#ifndef MMGR_INDEX_BITS
38#if MMGR_WORD_BITS < 32
39#define MMGR_INDEX_BITS MMGR_WORD_BITS
40#else
41#define MMGR_INDEX_BITS 32
42#endif
43#endif
44
45/**
46 * @brief Alignment applied to every carved region, and the granularity each pool must be a multiple of.
47 *
48 * @note MMGR_CARCER_CHECK asserts each pool is a whole number of these and at least two of them.
49 */
50#ifndef MMGR_ALIGN_BYTES
51
52#define MMGR_ALIGN_BYTES 16u
53#endif
54
55#include "config/mmgr_types.h"
56
57/**
58 * @brief Width in bits of one SWAR word, always equal to MMGR_WORD_BITS.
59 *
60 * @warning Any earlier definition is discarded. A build cannot set the two widths apart.
61 */
62#ifdef MMGR_SWAR_BITS
63#undef MMGR_SWAR_BITS
64#endif
65#define MMGR_SWAR_BITS MMGR_WORD_BITS
66
67/**
68 * @brief Set to 1 to enable the library's debug-only checks.
69 *
70 * @note Declared ahead of MMGR_ASSERT because it selects which of the two the assert becomes.
71 */
72#ifndef MMGR_DEBUG_CHECKS
73#define MMGR_DEBUG_CHECKS 0
74#endif
75
76/**
77 * @brief Runtime assertion hook: a trap under MMGR_DEBUG_CHECKS, inert otherwise.
78 *
79 * @param[in] cond Condition the caller expects to hold.
80 * @param[in] msg String literal describing the expectation.
81 * @note An expectation the library asserts is one a correct caller cannot break, and so the shipping
82 * form pays nothing for it: it expands to a sizeof, which type checks cond and never evaluates
83 * it. The checks build evaluates it instead and stops on the spot. A caller that broke one
84 * fails a test instead of carrying on with the damage done.
85 * @note A build may define its own before including this header, and neither form below is then used.
86 * A target with no stderr and no abort wants that.
87 * @warning With MMGR_DEBUG_CHECKS at 0, a failed expectation produces no diagnostic and no trap. It
88 * is not a runtime check and cannot be read as one.
89 */
90#ifndef MMGR_ASSERT
91#if MMGR_DEBUG_CHECKS
92#include <stdio.h>
93#include <stdlib.h>
94// fflush(NULL) before the trap, or a harness that buffers its progress on stdout loses every line of
95// it to the abort and reports the failure with nothing naming which case reached it
96#define MMGR_ASSERT(cond, msg) \
97 ((cond) ? (void)0 \
98 : (void)(fprintf(stderr, "MMGR_ASSERT failed: %s\n %s:%d\n", (msg), __FILE__, __LINE__), fflush(NULL), \
99 abort()))
100#else
101#define MMGR_ASSERT(cond, msg) ((void)sizeof((cond) ? 1 : 0), (void)0)
102#endif
103#endif
104
105/**
106 * @brief Bytes in the largest plaintext confinium this build will declare.
107 *
108 * @note Allocates nothing and sizes no pool. A pool's extent is an argument to mmgr_carcer_init, and
109 * nothing in carceribus reads this. It feeds MMGR_CARCER_MAX below, which is a
110 * bound other modules size their worst case against - so it is a statement of intent about the
111 * regions you are going to declare, and it wants raising if you declare a bigger one.
112 */
113#ifndef MMGR_PLAINTEXT_CONFIN_SIZE
114#define MMGR_PLAINTEXT_CONFIN_SIZE 4096u
115#endif
116
117/**
118 * @brief Bytes in the largest secure confinium this build will declare.
119 *
120 * @note The same kind of number as MMGR_PLAINTEXT_CONFIN_SIZE, and it sizes no pool either.
121 */
122#ifndef MMGR_SECURE_CONFIN_SIZE
123#define MMGR_SECURE_CONFIN_SIZE 4096u
124#endif
125
126/**
127 * @brief Bytes in the larger of the two confinia, bounding the worst case a scan or a read must cover.
128 *
129 * @note verbum_scrutor.h derives MMGR_SCAN_MAX_WORDS from this, and mmgr_string_shim.h uses it as MMGR_STR_MAX.
130 * @note The reason the bound exists is that these modules size a worst case at compile time instead
131 * of testing a length at run time. A string cannot be longer than the confinium holding it,
132 * and the confinium is the cap, and the scanner can be told how many words that is before it
133 * ever runs.
134 * @warning Declare a region larger than both knobs and this bound is under-stated. The static asserts
135 * in verbum_scrutor.h check that the word count covers this value, not that this value
136 * covers your regions, which nothing here can see.
137 */
138#ifndef MMGR_CARCER_MAX
139#if MMGR_PLAINTEXT_CONFIN_SIZE >= MMGR_SECURE_CONFIN_SIZE
140#define MMGR_CARCER_MAX ((size_t)MMGR_PLAINTEXT_CONFIN_SIZE)
141#else
142#define MMGR_CARCER_MAX ((size_t)MMGR_SECURE_CONFIN_SIZE)
143#endif
144#endif
145
146/**
147 * @brief Set to 1 to build the memoriam_praetereo DMA path.
148 *
149 * @note mmgr.h includes memoriam_praetereo.h only when this is set. The schedule's knobs are read in
150 * memoriam_praetereo/praet_praefinitum.h and memoriam_praetereo/praet_horologiorum_custos.h.
151 */
152#ifndef MMGR_ENABLE_DMA
153#define MMGR_ENABLE_DMA 0
154#endif
155/**
156 * @brief Set to 1 to build the confinium_externum external memory path.
157 *
158 * @note mmgr.h includes confinium_externum.h only when this is set.
159 */
160#ifndef MMGR_ENABLE_EXTRAM
161
162#define MMGR_ENABLE_EXTRAM 0
163#endif
164
165/**
166 * @brief Set to 1 to build the time-based ring behavior.
167 *
168 * @note MMGR_RING_ATTACH_US exists only when this is set.
169 */
170#ifndef MMGR_ENABLE_CLOCK
171#define MMGR_ENABLE_CLOCK 0
172#endif
173
174/**
175 * @brief Microseconds a ring waits before attaching.
176 *
177 * @warning Defined only when MMGR_ENABLE_CLOCK is set.
178 */
179#if MMGR_ENABLE_CLOCK
180#ifndef MMGR_RING_ATTACH_US
181#define MMGR_RING_ATTACH_US 100u
182#endif
183#endif
184
185/**
186 * @brief Fails the build unless x_ has type size_t.
187 *
188 * @param[in] x_ Expression whose type is checked.
189 * @note Evaluates to void; the _Generic association list admits size_t only.
190 */
191#define MMGR_MEMOR_IS_SIZE(x_) ((void)_Generic((x_), size_t: 0))
192
193/**
194 * @brief Fails the build unless x_ has type uint8_t.
195 *
196 * @param[in] x_ Expression whose type is checked.
197 * @note Evaluates to void; the _Generic association list admits uint8_t only.
198 */
199#define MMGR_MEMOR_IS_BYTE(x_) ((void)_Generic((x_), uint8_t: 0))
200
201/**
202 * @brief Defines a value-returning entry point that forwards an argument pack.
203 *
204 * @param PREFIX The public entry point prefix (e.g., mmgr_infin_)
205 * @param BACKEND The backend function prefix (e.g., infin_)
206 * @param CTX_TYPE The context structure type (e.g., InfinCtx)
207 * @param CFG_TYPE The config structure type (e.g., InfinCfg)
208 * @param RET_TYPE Return type of the function
209 * @param NAME The core name of the function
210 * @param ... The variadic argument pack/fields to forward
211 */
212#define GENERIC_ENTRY(PREFIX, BACKEND, CTX_TYPE, CFG_TYPE, RET_TYPE, NAME, ...) \
213 RET_TYPE PREFIX##NAME(const CFG_TYPE *c) \
214 { \
215 return MMGR_CALL(BACKEND##NAME, CTX_TYPE, __VA_ARGS__); \
216 }
217
218/**
219 * @brief Defines a void entry point that forwards an argument pack.
220 */
221#define GENERIC_ENTRY_V(PREFIX, BACKEND, CTX_TYPE, CFG_TYPE, NAME, ...) \
222 void PREFIX##NAME(const CFG_TYPE *c) \
223 { \
224 MMGR_CALL(BACKEND##NAME, CTX_TYPE, __VA_ARGS__); \
225 }
226
227#endif