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
@@ -169,4 +169,111 @@ uint64_t stadium_density(size_t cell_index) {
|
||||
return header->heat / (uint64_t)header->mass;
|
||||
}
|
||||
|
||||
#define STADIUM_FLAG_PIN 0x01u
|
||||
|
||||
static int bitmap_get(size_t cell_index) {
|
||||
return (stadium_bitmap[cell_index / 8u] >> (cell_index % 8u)) & 1u;
|
||||
}
|
||||
|
||||
static void bitmap_set(size_t cell_index) {
|
||||
stadium_bitmap[cell_index / 8u] |= (uint8_t)(1u << (cell_index % 8u));
|
||||
}
|
||||
|
||||
static void bitmap_clear(size_t cell_index) {
|
||||
stadium_bitmap[cell_index / 8u] &= (uint8_t)~(1u << (cell_index % 8u));
|
||||
}
|
||||
|
||||
/*
|
||||
* FABRIC.md §17.2: reap means leaves the floor, not destroyed. Refuses a
|
||||
* pinned header (§3) or one with a non-none `contains` (item 1.1: a patron
|
||||
* holding another cannot be reaped). Refuses an out-of-range index or a cell
|
||||
* whose discriminator bit is not set -- nothing resident there to reap.
|
||||
*/
|
||||
int stadium_evict(size_t cell_index) {
|
||||
StadiumPatronHeader *header;
|
||||
|
||||
if (cell_index >= stadium_ncells) return -1;
|
||||
if (!bitmap_get(cell_index)) return -1;
|
||||
|
||||
header = &stadium_cell_array[cell_index].header;
|
||||
if (header->flags & STADIUM_FLAG_PIN) return -1;
|
||||
if (header->contains != STADIUM_CONTAINS_NONE) return -1;
|
||||
|
||||
stadium_dispatch(cell_index, (StadiumBehaviour)header->behaviour);
|
||||
bitmap_clear(cell_index);
|
||||
|
||||
{
|
||||
uint8_t *raw = (uint8_t *)header;
|
||||
size_t i;
|
||||
for (i = 0; i < sizeof(*header); i++) raw[i] = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* FABRIC.md §19.3: admit if denser than the least-dense resident. Free-cell
|
||||
* placement first (no comparison needed -- §19.3 only governs the full
|
||||
* case); otherwise finds the least-dense evictable resident (pinned and
|
||||
* contains-gated residents are skipped, never eviction candidates) and
|
||||
* evicts it only if the candidate is strictly denser.
|
||||
*/
|
||||
size_t stadium_admit(const StadiumPatronHeader *candidate) {
|
||||
size_t i;
|
||||
size_t least_dense_index = STADIUM_CELL_NONE;
|
||||
uint64_t least_dense_value = 0;
|
||||
uint64_t candidate_density;
|
||||
|
||||
if (!stadium_initialized || !candidate) return STADIUM_CELL_NONE;
|
||||
|
||||
/* Multi-cell patrons need their continuation chain allocated too, which
|
||||
* needs the per-VM free lists item 3.2 deferred (§22.3) -- not this
|
||||
* item's scope. Refuse rather than admit only the header and leak the
|
||||
* rest, which would break capacity conservation. */
|
||||
if (candidate->mass != 1) return STADIUM_CELL_NONE;
|
||||
|
||||
/* contains must be a real "none" or a real index -- catches garbage/
|
||||
* uninitialized values, though not a zero-initialized candidate that
|
||||
* meant "none": 0 is Hera's valid index, so that case is a caller
|
||||
* contract issue this function cannot detect (see the header doc). */
|
||||
if (candidate->contains != STADIUM_CONTAINS_NONE &&
|
||||
candidate->contains >= stadium_ncells) return STADIUM_CELL_NONE;
|
||||
|
||||
for (i = 0; i < stadium_ncells; i++) {
|
||||
if (!bitmap_get(i) && stadium_cell_array[i].header.mass == 0) {
|
||||
stadium_cell_array[i].header = *candidate;
|
||||
bitmap_set(i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < stadium_ncells; i++) {
|
||||
StadiumPatronHeader *h;
|
||||
|
||||
if (!bitmap_get(i)) continue;
|
||||
h = &stadium_cell_array[i].header;
|
||||
if (h->flags & STADIUM_FLAG_PIN) continue;
|
||||
if (h->contains != STADIUM_CONTAINS_NONE) continue;
|
||||
|
||||
{
|
||||
uint64_t d = stadium_density(i);
|
||||
if (least_dense_index == STADIUM_CELL_NONE || d < least_dense_value) {
|
||||
least_dense_index = i;
|
||||
least_dense_value = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (least_dense_index == STADIUM_CELL_NONE) return STADIUM_CELL_NONE;
|
||||
|
||||
candidate_density = candidate->mass ? (candidate->heat / (uint64_t)candidate->mass) : 0;
|
||||
if (candidate_density <= least_dense_value) return STADIUM_CELL_NONE;
|
||||
|
||||
if (stadium_evict(least_dense_index) != 0) return STADIUM_CELL_NONE;
|
||||
|
||||
stadium_cell_array[least_dense_index].header = *candidate;
|
||||
bitmap_set(least_dense_index);
|
||||
return least_dense_index;
|
||||
}
|
||||
|
||||
#endif /* __STARKERNEL__ */
|
||||
Reference in New Issue
Block a user