starkernel: item 3.5 -- admission and eviction
Punch list §25 item 3.5 complete. stadium_admit(candidate) places into an unused cell if one exists (no comparison needed), otherwise finds the least-dense resident -- skipping pinned and contains-gated patrons, which are never eviction candidates -- and evicts it only if the candidate is strictly denser, per §19.3. stadium_evict(cell_index) dispatches the departing patron's behaviour before clearing its slot, per §17.2. Caught a real bug before it ran: the first draft used contains == 0 to mean "holds nothing," but cell index 0 is a valid index (Hera, item 3.6). Fixed with a proper sentinel, STADIUM_CONTAINS_NONE (UINT32_MAX). A second-pass review found mass was not accounted for: both functions handled exactly one cell regardless of the candidate's stated mass, which leaks cells on eviction of any mass > 1 patron and breaks capacity conservation. Fixed by refusing any candidate with mass != 1 -- multi-cell patrons need the per-VM free lists item 3.2 already deferred (§22.3), not built here. Documented, not fixed: the discriminator bitmap can't distinguish free from continuation cells, so the free-cell scan reads continuation-cell payload bytes under the header layout -- latent since nothing creates continuation cells yet, and the mass != 1 refusal keeps it provably latent. Superseded by the free list when it exists. Unexercised at runtime: nothing calls either function yet (no real patron kind is wired to the Stadium). No self-test added -- filling ~74,000+ cells to reach the eviction-on-full branch was judged impractical, following item 2.2's own precedent for its unexercised fleet-full path. Verified: three-architecture boot (amd64, aarch64, riscv64), all reaching ok> with identical dict_hash=0x3d4e1daf289da94f matching the item-3.4 baseline. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
0b47c256fc
commit
f8a50561b0
@@ -40,6 +40,11 @@
|
||||
|
||||
#define STADIUM_CELL_BYTES 64
|
||||
|
||||
/* Sentinel for `contains` meaning "holds no patron." Not 0 -- cell index 0 is
|
||||
* a valid index (Hera, item 3.6), so 0 cannot double as "none" without
|
||||
* conflating "contains Hera" with "contains nothing." */
|
||||
#define STADIUM_CONTAINS_NONE ((uint32_t)-1)
|
||||
|
||||
/*
|
||||
* StadiumPatronHeader - one member of the closed two-valued cell union
|
||||
* (FABRIC.md §3). Nine wires: identity, heat, TTL, pin (a bit in `flags`),
|
||||
@@ -58,9 +63,12 @@ typedef struct {
|
||||
uint64_t heat; /* offset 8 -- Q48.16, conserved share of 1.0 (§19.1) */
|
||||
uint32_t ttl; /* offset 16 -- remaining lifetime; messages and ACLs only (§17.1) */
|
||||
uint32_t link; /* offset 20 -- index into the Stadium, not a pointer */
|
||||
uint32_t contains; /* offset 24 -- index of the patron held inside this one, or none (item 1.1).
|
||||
* Chains up to STADIUM_CONTAINS_DEPTH_MAX deep; reap-gating
|
||||
* enforcement of that bound is item 3.5's scope, not this one's. */
|
||||
uint32_t contains; /* offset 24 -- index of the patron held inside this one, or
|
||||
* STADIUM_CONTAINS_NONE (item 1.1). Cell index 0 is a valid
|
||||
* index (Hera, item 3.6) so 0 cannot mean "none" -- item 3.5
|
||||
* caught this and picked UINT32_MAX instead. Chains up to
|
||||
* STADIUM_CONTAINS_DEPTH_MAX deep; reap-gating enforcement of
|
||||
* that bound is item 3.5's scope. */
|
||||
uint16_t mass; /* offset 28 -- cells this patron occupies (§19.2) */
|
||||
uint8_t flags; /* offset 30 -- bit 0 = pin; remaining bits reserved */
|
||||
uint8_t behaviour; /* offset 31 -- code field. Valid values are StadiumBehaviour (§18.3)
|
||||
@@ -201,6 +209,67 @@ void stadium_dispatch(size_t cell_index, StadiumBehaviour behaviour);
|
||||
*/
|
||||
uint64_t stadium_density(size_t cell_index);
|
||||
|
||||
/* Sentinel returned by stadium_admit() on refusal -- no cell index is this large. */
|
||||
#define STADIUM_CELL_NONE ((size_t)-1)
|
||||
|
||||
/*
|
||||
* stadium_evict - Reap the patron header at cell_index (FABRIC.md §17.2:
|
||||
* "reap means leaves the floor, not destroyed"). Dispatches its behaviour
|
||||
* (§18.3), clears its item-3.1 discriminator bit, zeroes its header.
|
||||
*
|
||||
* Refuses if the header is pinned (`flags` bit 0, §3's invariance wire) or
|
||||
* has a non-none `contains` (item 1.1: a patron holding another cannot be
|
||||
* reaped, full stop). Also refuses for an out-of-range index or a cell whose
|
||||
* discriminator bit is not set (nothing resident there to reap).
|
||||
*
|
||||
* @param cell_index Index of the patron header to reap.
|
||||
* @return 0 on success, -1 if refused.
|
||||
*/
|
||||
int stadium_evict(size_t cell_index);
|
||||
|
||||
/*
|
||||
* stadium_admit - Place a candidate patron header into the Stadium (FABRIC.md
|
||||
* §19.3).
|
||||
*
|
||||
* First scans for an unused cell (discriminator bit clear and mass == 0) and
|
||||
* places the candidate there directly -- §19.3's density comparison only
|
||||
* governs the full case, not this one. If none is free, finds the
|
||||
* least-dense resident (discriminator bit set, mass > 0, not pinned, not
|
||||
* `contains`-gated -- pinned and gated residents are never eviction
|
||||
* candidates, per §3 and item 1.1) and evicts it via stadium_evict() only if
|
||||
* the candidate is strictly denser (§19.3: "denser than," not "at least as
|
||||
* dense as"). Otherwise refuses.
|
||||
*
|
||||
* Does not itself assert anything about which resident this turns out to be
|
||||
* -- the item-3.6 rule that patron zero (Hera) must never actually be
|
||||
* selected is a separate, later check at the eviction site.
|
||||
*
|
||||
* REFUSES any candidate with mass != 1. A multi-cell patron (mass > 1, e.g.
|
||||
* §23.3's 1024-byte block at mass 19) needs its continuation chain allocated
|
||||
* too, which needs the per-VM free lists §22.3 describes -- item 3.2's DONE
|
||||
* note already deferred those (not this item's scope, they are granted when
|
||||
* Hera assigns a VM its quota). Admitting only the header and leaking the
|
||||
* rest would break capacity conservation, so this refuses rather than doing
|
||||
* that. Revisit when the free lists exist.
|
||||
*
|
||||
* REQUIRES candidate->contains to be either STADIUM_CONTAINS_NONE or a valid
|
||||
* index (< the current cell count) -- refuses otherwise. This does NOT catch
|
||||
* a zero-initialized candidate that was meant to contain nothing: 0 is a
|
||||
* valid index (Hera), so a caller that forgets to set `contains` explicitly
|
||||
* to STADIUM_CONTAINS_NONE will admit a patron that reads as "contains
|
||||
* Hera" and is therefore permanently un-evictable. There is no way to tell
|
||||
* "meant to be 0" from "forgot to set it" from inside this function --
|
||||
* callers must set every field, `contains` included.
|
||||
*
|
||||
* @param candidate Header to admit. Copied into the winning cell as-is;
|
||||
* caller fills in every field including mass and heat.
|
||||
* @return The cell index admitted into, or STADIUM_CELL_NONE if refused
|
||||
* (mass != 1, invalid contains, Stadium full and candidate not
|
||||
* denser than the least-dense evictable resident, or no evictable
|
||||
* resident exists at all).
|
||||
*/
|
||||
size_t stadium_admit(const StadiumPatronHeader *candidate);
|
||||
|
||||
#endif /* __STARKERNEL__ */
|
||||
|
||||
#endif /* STARKERNEL_VM_STADIUM_H */
|
||||
Reference in New Issue
Block a user