starkernel: item 4.1a -- quota granting, Hermes's one-time birth grant
Punch list §25 item 4.1a complete. New prerequisite item, found while scoping 4.2: no quota-granting mechanism existed at all. Adds stadium_grant_quota(new_vm_id, from_vm_id) -- a one-time initial grant at birth, distinct from item 1.3's still-unbuilt recurring capacity-transfer arbitration. Splits the donor's free list evenly by cell count, reassigns stadium_owner[] for every moved cell, and grants the new VM a fresh Q48_ONE reservoir (not a split of the donor's -- per-VM conservation, same pattern as Hera's own boot grant). Wired into every baby VM's birth in capsule_birth.c. Verified via a boot-time self-test in kernel_main.c using a synthetic identity (not the real UUID pool, not a real capsule birth -- item 0.1's Hera-alone pruning stays intact). All three architectures booted to ok> with identical output: grant OK, Hera reservoir=0 (already fully committed to resident words, correctly unchanged), test-vm reservoir=65536 (fresh Q48_ONE). dict_hash identical across all three and unchanged from item 4.1's baseline (0x3d4e1daf289da94f) -- confirms no dictionary word was added. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
edfc246579
commit
2981ada2a5
@@ -398,6 +398,61 @@ size_t stadium_admit(VMUuid vm_id, const StadiumPatronHeader *candidate) {
|
||||
return idx;
|
||||
}
|
||||
|
||||
/*
|
||||
* FABRIC.md item 4.1a: one-time initial quota grant, not item 1.3's
|
||||
* (still-unbuilt) recurring transfer. See stadium.h's doc for the full
|
||||
* argument. Two passes over from_vm_id's free list: the first counts it
|
||||
* (need the length before deciding where to split), the second detaches the
|
||||
* first `half` cells into new_vm_id's own list, reassigning owner as it goes.
|
||||
*/
|
||||
int stadium_grant_quota(VMUuid new_vm_id, VMUuid from_vm_id) {
|
||||
int from_slot, new_slot, i;
|
||||
size_t count, half, idx, last_new, new_head, remainder_head;
|
||||
|
||||
if (!stadium_initialized) return -1;
|
||||
if (quota_slot_for_vm(new_vm_id) >= 0) return -1;
|
||||
|
||||
from_slot = quota_slot_for_vm(from_vm_id);
|
||||
if (from_slot < 0) return -1;
|
||||
|
||||
new_slot = -1;
|
||||
for (i = 0; i < STADIUM_MAX_VM_COUNT; i++) {
|
||||
if (!stadium_quotas[i].in_use) { new_slot = i; break; }
|
||||
}
|
||||
if (new_slot < 0) return -1;
|
||||
|
||||
count = 0;
|
||||
idx = stadium_quotas[from_slot].free_head;
|
||||
while (idx != STADIUM_CELL_NONE) {
|
||||
count++;
|
||||
idx = link_to_size(stadium_cell_array[idx].header.link);
|
||||
}
|
||||
|
||||
half = count / 2;
|
||||
if (half == 0) return -1; /* fewer than 2 free cells -- nothing to split */
|
||||
|
||||
new_head = stadium_quotas[from_slot].free_head;
|
||||
idx = new_head;
|
||||
last_new = STADIUM_CELL_NONE;
|
||||
for (i = 0; i < (int)half; i++) {
|
||||
stadium_owner[idx] = (uint8_t)new_slot;
|
||||
last_new = idx;
|
||||
idx = link_to_size(stadium_cell_array[idx].header.link);
|
||||
}
|
||||
/* idx now points to the first cell staying with from_slot (or
|
||||
* STADIUM_CELL_NONE if half == count, i.e. an even list fully moved). */
|
||||
remainder_head = idx;
|
||||
stadium_cell_array[last_new].header.link = size_to_link(STADIUM_CELL_NONE);
|
||||
stadium_quotas[from_slot].free_head = remainder_head;
|
||||
|
||||
stadium_quotas[new_slot].vm_id = new_vm_id;
|
||||
stadium_quotas[new_slot].in_use = 1;
|
||||
stadium_quotas[new_slot].free_head = new_head;
|
||||
stadium_quotas[new_slot].reservoir = Q48_ONE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t stadium_reservoir_pull(VMUuid vm_id, uint64_t amount) {
|
||||
int slot = quota_slot_for_vm(vm_id);
|
||||
uint64_t pulled;
|
||||
|
||||
Reference in New Issue
Block a user