Expand description
phase-412 #4 — the arena’s HOST ORACLE, held to at compile time.
nros-node/build.rs is the one place that knows what this image’s declared
entities cost: it sums the per-kind model over NROS_ENTITY_COUNT_* (and the
declared depths) and emits the result as arena_model::REQUIRED beside
the arena it derives from it (cargo:arena_size). Before this module that
requirement stopped at the derivation. An image that STATED
NROS_EXECUTOR_ARENA_SIZE below it built, linked, flashed and then died at
the first registration that did not fit, with NodeError::BufferTooSmall —
on a board whose only diagnostic channel may be a RAM record read back with
a debugger (issue 1036).
Here the two numbers meet in one compilation, so the refusal is a build error that names the knob, both numbers and the shortfall.
§Which arms can be held, and which cannot
The arena is a slice of caller-supplied backing, so “the arena” is really one number per PLACEMENT. A compile-time check needs the arena and the requirement to be constants in the same compilation; that decides it.
| arm | arena comes from | checked |
|---|---|---|
Rust .bss EXECUTOR_BACKING | ExecutorSizing::DEFAULT.arena = ARENA_SIZE | compile time, the ARENA_SIZE const item below |
Rust heap, default sizing (open / open_multi / open_with_rmw past the static) | the same DEFAULT | compile time, same assertion |
C rclc_executor_t::_opaque | EXECUTOR_OPAQUE_U64S, measured from ExecutorInlineStorage = DEFAULT | compile time, same assertion (nros-c compiles after it) |
C++ Node::GlobalStorageHolder / Executor::storage_ | CPP_EXECUTOR_OPAQUE_U64S, measured the same way | compile time, same assertion |
Rust open_in over a caller’s const sizing | the caller’s ExecutorSizing::arena | compile time, OPT-IN: ExecutorSizing::assert_covers_model |
Rust heap, per-entry sizing (open_sized, arena_size_for(cbs)) | a RUNTIME cbs handed through BoardEntry | NO — runtime |
Rust open_in over a runtime slice / runtime sizing | runtime values | NO — runtime |
The runtime arms are not faked. Their arena is a value, not a constant, and
an executor there may hold a SUBSET of the image (a tier), so the
image-wide model is not even the right bound. What they get is the
registration-time refusal every arm already has: arena_alloc and
arena_alloc_with_trailing report the entity, the shortfall and the knob
(report_arena_exhausted, issues 0900 / 1036) and write the shortfall to
the boot record.
§What the model is, and what it is not
REQUIRED is the per-kind sum, whose terms
executor::arena asserts to be upper bounds on the entry types they stand
for. So an arena at or above it fits what was declared. It is NOT a lower
bound on what an image needs: the terms over-price (issue 1255 prices every
subscription at one image-wide type bound), so an arena stated below the
model may still fit. The refusal is deliberate anyway — a number below the
model is a claim the build cannot check, and the tree’s answer to an
over-priced model is to correct the model’s INPUTS (declared depths,
NROS_PUBSUB_QOS_DEPTH, per-type bounds), which re-derive the arena, rather
than to hand-state a number that goes stale the next time any term moves.
An image that declares nothing has REQUIRED == 0: the derivation then
budgeted a worst case over NROS_EXECUTOR_MAX_CBS slots, which is a budget
and not a requirement, and stating less than a budget is the ordinary use of
the knob. Nothing is refused there.
Functions§
- assert_
covers_ model - Refuse, during CONST EVALUATION, an arena below this image’s model.
- shortfall
- Bytes
arenafalls short of this image’s modelled requirement;0when it covers it, or when the image declared nothing.