ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
guardrails.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file guardrails.h
6 * @brief Runtime heap/stack guardrails (PROTOCORE_ENABLE_GUARDRAILS).
7 *
8 * Samples the live health of the device - free heap, the heap low-water mark, the
9 * largest free block (a fragmentation signal), and the calling task's remaining
10 * stack - and trips a guardrail (callback) when any value crosses its configured
11 * floor. A proactive fail-safe hook on top of the passive numbers in /metrics: an
12 * app can shed load, drop to a safe state, or reboot before exhaustion bites.
13 *
14 * The threshold evaluator and the JSON serializer are pure and host-tested; the
15 * sample reads `esp_get_free_heap_size` / `heap_caps_get_largest_free_block` /
16 * `uxTaskGetStackHighWaterMark` on ESP32 (zeros on host).
17 *
18 * @author Douglas Quigg (dstroy0)
19 * @date 2026
20 */
21
22#ifndef PROTOCORE_GUARDRAILS_H
23#define PROTOCORE_GUARDRAILS_H
24
25#include "protocore_config.h" // the entry point: protocore_types.h for the widths
26
27#if PROTOCORE_ENABLE_GUARDRAILS
28
30
31/** @brief A health snapshot. */
32typedef struct
33{
34 uint32_t free_heap; ///< current free heap (bytes).
35 uint32_t min_free_heap; ///< lowest free heap since boot (bytes).
36 uint32_t largest_free_block; ///< largest allocatable block (fragmentation, bytes).
37 uint32_t stack_free; ///< calling task's remaining stack (bytes).
38} protocore_health;
39
40/** @brief Guardrail breach flags: a bitmask OR'd together, so integer constants in a namespacing
41 * struct (cast-free at every | / &). */
42#define PROTOCORE_BREACH_NONE 0
43#define PROTOCORE_BREACH_HEAP 1 ///< free heap below PROTOCORE_GUARDRAIL_HEAP_MIN.
44#define PROTOCORE_BREACH_FRAG 2 ///< largest block below PROTOCORE_GUARDRAIL_FRAG_MIN_BLOCK.
45#define PROTOCORE_BREACH_STACK 4 ///< task stack remaining below PROTOCORE_GUARDRAIL_STACK_MIN.
46
47/** @brief Breach callback: @p breaches is a PROTOCORE_BREACH_* bitmask, @p h the snapshot. */
48typedef void (*protocore_breach_fn)(uint8_t breaches, const protocore_health *h);
49
50/** @brief The floors an evaluation judges a snapshot against. */
51typedef struct
52{
53 uint32_t heap_min; ///< free heap under this trips PROTOCORE_BREACH_HEAP
54 uint32_t frag_min_block; ///< largest block under this trips PROTOCORE_BREACH_FRAG
55 uint32_t stack_min; ///< stack remaining under this trips PROTOCORE_BREACH_STACK
56} GuardrailFloorArgs;
57
58/** @brief Where a serialize writes. */
59typedef struct
60{
61 char *out; ///< the buffer the JSON lands in
62 size_t cap; ///< how much room it has
63} GuardrailOutArgs;
64
65/**
66 * @brief The device's live health, and the floors it is judged against.
67 *
68 * A caller sets the members a call takes, invokes it through ::Guardrails, and reads the outcome
69 * off the same handle.
70 *
71 * @var GuardrailsNs::health the snapshot a call fills, judges, or serializes
72 * @var GuardrailsNs::floors what an eval judges against
73 * @var GuardrailsNs::out where a json writes
74 * @var GuardrailsNs::cb the callback a begin installs
75 * @var GuardrailsNs::breaches the PROTOCORE_BREACH_* bitmask an eval or a check reports
76 * @var GuardrailsNs::n characters a json wrote, 0 when it did not fit
77 * @var GuardrailsNs::eval judge @ref health against @ref floors
78 * @var GuardrailsNs::json serialize @ref health
79 * @var GuardrailsNs::sample fill @ref health from the live counters
80 * @var GuardrailsNs::begin install the breach callback
81 * @var GuardrailsNs::check sample, judge against PROTOCORE_GUARDRAIL_*, fire on a breach
82 */
83typedef struct
84{
85 protocore_health *health;
86 GuardrailFloorArgs floors;
87 GuardrailOutArgs out;
88 protocore_breach_fn cb;
89 uint8_t breaches;
90 int n;
91} GuardrailsVars;
92
93/** @brief The operands and the outcome. */
94extern GuardrailsVars GuardrailsV;
95
96/** @brief The entries. */
97typedef struct
98{
99 void (*const eval)(uint8_t *work);
100 void (*const json)(uint8_t *work);
101 void (*const sample)(uint8_t *work);
102 void (*const begin)(uint8_t *work);
103 void (*const check)(uint8_t *work);
104} GuardrailsNs;
105
106// What the table binds, defined once in the .c and taking one parameter each: everything
107// else an entry needs is an operand in GuardrailsV or a region of the borrow at a fixed offset.
108void protocore_guardrails_eval(uint8_t *work);
109void protocore_guardrails_json(uint8_t *work);
110void protocore_guardrails_sample(uint8_t *work);
111void protocore_guardrails_begin(uint8_t *work);
112void protocore_guardrails_check(uint8_t *work);
113
114// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
115// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
116// `Guardrails.eval(work)` resolves to a named function and becomes a DIRECT call. An extern table
117// leaves the call indirect and the symbol live at every level, -O2 -flto included.
118static const GuardrailsNs Guardrails __attribute__((unused)) = {
119 .eval = protocore_guardrails_eval,
120 .json = protocore_guardrails_json,
121 .sample = protocore_guardrails_sample,
122 .begin = protocore_guardrails_begin,
123 .check = protocore_guardrails_check,
124};
125
126/**
127 * @brief The PROTOCORE_GUARDRAILS_BORROW bytes this module's state lives in.
128 *
129 * Stated beside the namespace rather than on it: an entry takes a borrow, and this is where
130 * that borrow comes from. Taken once from the end of the pool, which no mark and no release
131 * walks, so the state lasts the life of the program.
132 *
133 * @return the span.
134 */
135uint8_t *protocore_guardrails_span(void);
136
138
139#endif // PROTOCORE_ENABLE_GUARDRAILS
140
141#endif // PROTOCORE_GUARDRAILS_H
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
#define PROTOCORE_END_DECLS
Definition types.h:97