Add sk_hermes_alloc(), the heat-coupled allocator -- FABRIC-3.6.md task 2.2, item 28
The piece FABRIC-3.5.md SXXXIII.6 calls "what remains genuinely hard,"
built and proven first per its own recommendation. Added
src/starkernel/vm/kernel_hermes.c (wired into Makefile.starkernel's
LOADER_EXTRA_SRCS -- this repo lists vm/*.c files explicitly, no glob)
and sk_hermes_alloc()'s declaration in kernel_hermes.h.
Checks stadium_reservoir_peek(vm_id) >= SK_HERMES_Q_SLOT before
touching the reservoir at all -- refusal this way needs no rollback,
since nothing was pulled -- with an explicit rollback path
(stadium_reservoir_push) kept defensively for the pull-then-short case,
though nothing in this single-core kernel is expected to reach it.
SK_HERMES_Q_SLOT = Q48_ONE / SK_HERMES_MSG_MAX (2048), deliberately
simpler than messaging.4th's own formula, which reserves a Q.1/3 floor
for COMMON-CH's own Stadium heat -- kernel-Hermes has no such object
(SXXXIII.4/SXXXIII.5's flat membership list carries no heat of its
own), so there is nothing left for that floor to protect.
Self-test in kernel_main.c, same diagnostic-only synthetic-VM pattern
as the existing Stadium quota grant self-test (lo=3, distinct from
that test's lo=1): reads back the actual granted reservoir rather than
assuming a number, derives expected_n from it, allocates to refusal,
and checks the refusal lands at exactly expected_n, the reservoir
doesn't move on the refused attempt (rollback proven, not assumed),
and the final reservoir is exactly reservoir0 minus got_n times
Q_SLOT.
Three-arch boot clean: amd64/aarch64/riscv64 all reach [zuse@Hera] ok>,
zero UNKNOWN WORD, dict_hash unmoved from task 2.1 (pure C, no FORTH
touched). All three print identical self-test arithmetic: reservoir0=
65536 Q_SLOT=2048 expected_n=32 got_n=32 reservoir_after=0. No compiler
warnings.
Noted, not fixed: Q_SLOT's divisor and SK_HERMES_MSG_MAX are the same
32, so reservoir and arena exhaustion land at exactly the same count by
construction -- this test can't distinguish which refusal reason
fired, only that refusal is correct and rolls back correctly.
Deliberately not evidence for stadium_conserved(): allocating alone
(no release yet, task 2.3) leaves pulled heat held off the Stadium
floor, so the two-term check would correctly read false right now if
run mid-hold. That's expected, not a bug -- Stage B (task 2.7) is
defined as "before and after the alloc/free cycle," not "continuously
during." This task's self-test checks reservoir arithmetic directly
instead.
Authorized by Captain Bob ("Yes continue").
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
f10fa7ae83
commit
9d129fdb1c
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
StarForth — Steady-State Virtual Machine Runtime
|
||||
|
||||
Copyright (c) 2023–2025 Robert A. James
|
||||
All rights reserved.
|
||||
|
||||
This file is part of the StarForth project.
|
||||
|
||||
Licensed under the StarForth License, Version 1.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at:
|
||||
https://github.com/star.4th@proton.me/StarForth/LICENSE.txt
|
||||
|
||||
This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
express or implied, including but not limited to the warranties of
|
||||
merchantability, fitness for a particular purpose, and noninfringement.
|
||||
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* kernel_hermes.c - Kernel-resident Hermes: the heat-coupled allocator
|
||||
* (FABRIC-3.6.md task 2.2, item 28).
|
||||
*/
|
||||
|
||||
#ifdef __STARKERNEL__
|
||||
|
||||
#include <string.h>
|
||||
#include "starkernel/vm/kernel_hermes.h"
|
||||
#include "starkernel/vm/stadium.h"
|
||||
|
||||
static SkHermesMessage sk_hermes_msgs[SK_HERMES_MSG_MAX];
|
||||
|
||||
static int sk_hermes_find_free_slot(void) {
|
||||
int i;
|
||||
for (i = 0; i < SK_HERMES_MSG_MAX; i++) {
|
||||
if (!sk_hermes_msgs[i].in_use) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sk_hermes_alloc(VMUuid vm_id, SkHermesMessage **out_msg) {
|
||||
int slot;
|
||||
uint64_t pulled;
|
||||
|
||||
if (!out_msg) return -1;
|
||||
|
||||
/* Check affordability before touching the reservoir at all -- this is
|
||||
* what "roll back on refusal" reduces to when the check happens
|
||||
* first: there is nothing to roll back. */
|
||||
if (stadium_reservoir_peek(vm_id) < SK_HERMES_Q_SLOT) return -1;
|
||||
|
||||
slot = sk_hermes_find_free_slot();
|
||||
if (slot < 0) return -1; /* arena full, reservoir untouched */
|
||||
|
||||
pulled = stadium_reservoir_pull(vm_id, SK_HERMES_Q_SLOT);
|
||||
if (pulled < SK_HERMES_Q_SLOT) {
|
||||
/* Should not happen given the peek check above (nothing else runs
|
||||
* between the two calls on this single-core, cooperative kernel),
|
||||
* but roll back explicitly rather than trust that invariant
|
||||
* silently. */
|
||||
if (pulled > 0) stadium_reservoir_push(vm_id, pulled);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&sk_hermes_msgs[slot], 0, sizeof(SkHermesMessage));
|
||||
sk_hermes_msgs[slot].in_use = 1;
|
||||
*out_msg = &sk_hermes_msgs[slot];
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __STARKERNEL__ */
|
||||
Reference in New Issue
Block a user