Stage E: every born VM is a switch participant (FABRIC-3.8 §3.6, G4)
capsule_birth_baby() registers each VM at its LIVE completion point, beside the common-channel subscription. register() is idempotent. The Artemis/ Hestia registrations in kernel_main.c and WIREBIND's own call are removed (Hera, never born through capsule_birth_baby, stays with set_current). Probe (restored away): Tripod registered once each (3 slots), a WORKER-BIRTH VM becomes a participant with no hand registration (4) and KILL frees it (3), WIREBIND registers exactly console+user, zero duplicates, on amd64/aarch64/riscv64. Acceptance: dict_hash unchanged, relay 3, idle growth 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
604ad7aadc
commit
c7185facf0
@@ -920,6 +920,20 @@ CapsuleRunResult capsule_birth_baby(
|
||||
* and does not fail the birth itself. */
|
||||
(void)sk_hermes_channel_subscribe(SK_HERMES_CHANNEL_COMMON, vm_id);
|
||||
|
||||
/* FABRIC-3.8.md §3.6 (Stage E, G4): every born VM is a switch
|
||||
* participant -- same choke point, same "only once birth has fully
|
||||
* completed" rule as the subscription above (its capsule code has
|
||||
* already run to completion on the birthing VM's stack). BIRTH,
|
||||
* WORKER-BIRTH, UNATTENDED-BIRTH and WIREBIND identities all pass
|
||||
* through here, so none of them registers on its own any more. Soft
|
||||
* failure, same posture: a full table leaves this VM runnable only by
|
||||
* VM-EXEC, not a failed birth. A VM with no native stack is registered
|
||||
* but never chosen (sk_vm_switch_decide() skips it). */
|
||||
if (sk_vm_switch_signal_register(vm_id) < 0) {
|
||||
log_message(LOG_WARN, "capsule_birth_baby: switch-signal table full -- %s won't be switched to",
|
||||
capsule_name);
|
||||
}
|
||||
|
||||
capsule_parity_log_birth(vm_id, cap->capsule_id, cap->content_hash, dict_hash);
|
||||
|
||||
/* §H.12 step 11: applied AFTER dict_hash/parity logging above, not
|
||||
|
||||
@@ -143,6 +143,11 @@ int sk_vm_switch_signal_boot_init(void) {
|
||||
}
|
||||
|
||||
int sk_vm_switch_signal_register(VMUuid vm_id) {
|
||||
/* FABRIC-3.8.md §3.6 (Stage E): idempotent. Registration now happens
|
||||
* once, at birth; a second call returns the existing slot rather than
|
||||
* allocating a duplicate that the decision would walk twice. */
|
||||
int existing = slot_for_vm_id(vm_id);
|
||||
if (existing >= 0) return existing;
|
||||
if (g_slot_count >= g_slot_capacity) return -1;
|
||||
g_slots[g_slot_count].vm_id = vm_id;
|
||||
g_slots[g_slot_count].parked_stamp = 0;
|
||||
|
||||
@@ -80,9 +80,11 @@ typedef struct {
|
||||
struct blkio_dev *dev;
|
||||
VMUuid user_vm_id;
|
||||
char username[USER_IDENTITY_USERNAME_MAX];
|
||||
int switch_slot; /* Stage 4: index into the switch-signal
|
||||
* table, or -1 if not yet registered
|
||||
* (wired in the next increment). */
|
||||
int switch_slot; /* Stage 4: >= 0 if the user VM is a
|
||||
* switch-signal participant, -1 if not
|
||||
* (table full). FABRIC-3.8.md Stage E:
|
||||
* a flag, not a slot index -- indices
|
||||
* shift when the table compacts. */
|
||||
} wirebind_live_entry_t;
|
||||
|
||||
static wirebind_live_entry_t g_wirebind_live[WIREBIND_MAX_LIVE];
|
||||
@@ -313,7 +315,12 @@ void capsule_wirebind_try_attach(struct blkio_dev *dev,
|
||||
* failed attach -- the identity is still fully usable via
|
||||
* ordinary VM-EXEC/console-relay dispatch, same as before
|
||||
* Stage 4 existed. */
|
||||
live->switch_slot = sk_vm_switch_signal_register(user_id);
|
||||
/* FABRIC-3.8.md §3.6 (Stage E): no longer registered here --
|
||||
* capsule_birth_baby() registered the user VM (and, now, the
|
||||
* console VM too: harmless, it never has mail, so it is never
|
||||
* chosen) at birth. This only records whether that succeeded,
|
||||
* which is all switch_slot has ever been used for (>= 0). */
|
||||
live->switch_slot = sk_vm_switch_signal_is_participant(user_id) ? 0 : -1;
|
||||
memcpy(live->username, username, sizeof(live->username));
|
||||
if (live->switch_slot < 0) {
|
||||
console_println("WIREBIND: switch-signal table full -- this identity won't be preempted");
|
||||
|
||||
@@ -1255,8 +1255,15 @@ static void kernel_main_deep(BootInfo *boot_info) {
|
||||
* Artemis's own birth sequencing. FABRIC-3.6.md Phase 4 (Stage E),
|
||||
* 2026-09-22: Hermes's own registration here is retired along with
|
||||
* her birth above. */
|
||||
/* FABRIC-3.8.md §3.6 (Stage E, 2026-09-23): Artemis and Hestia are no
|
||||
* longer registered here -- capsule_birth_baby() registers every born
|
||||
* VM at its own LIVE completion point, which they already passed. Hera
|
||||
* is the one VM never born through it, so she is still registered
|
||||
* here, and this is still where the switch mechanism learns she is the
|
||||
* one running. Nothing can switch before sk_vm_switch_set_current():
|
||||
* every switch point requires a current VM. */
|
||||
{
|
||||
VMRegistryEntry hera_entry, artemis_entry;
|
||||
VMRegistryEntry hera_entry;
|
||||
if (capsule_vm_registry_get(vm_uuid_hera(), &hera_entry) == 0) {
|
||||
sk_vm_switch_signal_register(hera_entry.vm_id);
|
||||
/* Seed the switch mechanism's own "who is running" tracker
|
||||
@@ -1265,21 +1272,6 @@ static void kernel_main_deep(BootInfo *boot_info) {
|
||||
* ever happened. */
|
||||
sk_vm_switch_set_current(mama);
|
||||
}
|
||||
if (capsule_vm_find_by_name_nocase("Artemis", &artemis_entry) == 0 &&
|
||||
artemis_entry.state == VM_STATE_LIVE) {
|
||||
sk_vm_switch_signal_register(artemis_entry.vm_id);
|
||||
}
|
||||
/* Hestia is the third fleet member through Phase 4 (FABRIC-3.5.md
|
||||
* SXXXIV.4) -- FABRIC-3.6.md task 1.5, same registration shape as
|
||||
* Artemis above, added here rather than earlier for the
|
||||
* identical reason the comment above this block already gives. */
|
||||
{
|
||||
VMRegistryEntry hestia_entry;
|
||||
if (capsule_vm_find_by_name_nocase("Hestia", &hestia_entry) == 0 &&
|
||||
hestia_entry.state == VM_STATE_LIVE) {
|
||||
sk_vm_switch_signal_register(hestia_entry.vm_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* FABRIC-3.6.md task 3.2 (B1) self-test: confirm every live fleet
|
||||
|
||||
Reference in New Issue
Block a user