fix(hermes): one delivery path -- a VM takes its own messages on its own turn, never on another's stack
FABRIC-3.5 SXXXII, closing FABRIC-3 SXXIX bug 2 (SXXXVI). A send marks the receiver for the switch signal; the VM's own loop on its native stack takes its messages and yields; Hera's idle beat makes the pending switch instead of running other VMs' messages on her stack; every VM gets switcher turns from birth; the drain refuses any call outside the VM's own context (the test: it held every relayed line before, none now). Found on the way: amd64's first-entry frame left rsp 8 bytes off the SysV entry alignment (#GP on the first interpreter run on a VM's own stack), and a VM yielding from its loop was marked SWITCHED_OUT, which stopped console relay after one message and would have made KILL refuse it. Relay of four lines to a WIREBIND identity on all three ISAs, five hot-plugged identities, and standard acceptance (POST 1052, hash 0x08873e0f44b7cb2a) all pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
b7e8e4b058
commit
029a8ed9cf
+57
-1
@@ -3992,7 +3992,7 @@ are attached reliably in the first place, including under the "already plugged i
|
||||
case §XIV's own second reproduction showed failing.
|
||||
|
||||
**Bug 2 -- the MSG-TICK/Stage-3-switch dual-ownership rough edge (§XXVIII's own admission,
|
||||
never revisited).** Both MSG-TICK's idle-pump dispatch and the Stage 3 timer-driven switcher can
|
||||
never revisited).** *Closed 2026-10-14: one delivery path, built -- §XXXVI.* Both MSG-TICK's idle-pump dispatch and the Stage 3 timer-driven switcher can
|
||||
independently move control between the same VMs; not reconciled, not observed to interact badly
|
||||
so far, but never proven safe under all interleavings either. Directly relevant to Stage 4 for
|
||||
the same reason as Bug 1: WIREBIND VMs bring a second population of dynamically-birthed contexts
|
||||
@@ -5524,3 +5524,59 @@ device it was minted on.
|
||||
design/decision only, no capsule/C code, no new disk image, and no re-mint actually performed
|
||||
or committed for the drive resize, the persistence region, or the N=2 campaign shape.
|
||||
|
||||
|
||||
## XXXVI. One delivery path: a VM takes its own messages, on its own turn -- built (2026-10-14)
|
||||
|
||||
Closes the MSG-TICK/Stage-3 dual-ownership item (§XXVIII, §XXIX bug 2, §XXXI), as ruled in
|
||||
`FABRIC-3.5.md` §XXXII ("one mover"); Captain Bob, 2026-10-14: collapse it before the bare-metal
|
||||
builds. **The state before:** the MSG-TICK pump was gone (FABRIC-3.6 Stage E), but two paths
|
||||
still ran a VM's kernel-Hermes messages -- the VM's own outermost colon-word checkpoint, and
|
||||
Hera's idle beat, which walked every live VM and ran each one's messages *for* it, on Hera's
|
||||
stack. The second was the only path for a VM nothing else drives (a WIREBIND identity's `~user`
|
||||
VM, FABRIC-3.6 task 3.9). It was guarded (parked VMs are not LIVE and were skipped) but it was
|
||||
two paths.
|
||||
|
||||
**What changed.**
|
||||
- `sk_hermes_send_one()` marks the receiver as having work for the switch signal.
|
||||
- What a VM runs on its own native stack (`sk_vm_switch_entry()`, until now a placeholder that
|
||||
only yielded) now takes its own messages, then yields. Not while its interpreter is mid-line on
|
||||
some other, parked, stack (new per-VM `interpret_depth`, counted in `vm_interpret()`): then
|
||||
they wait and it asks for another turn.
|
||||
- Hera's idle beat no longer runs anyone's messages but her own; it makes the switch the switch
|
||||
signal has pending (`sk_vm_switch_service_pending()`, shared with the colon-word checkpoint),
|
||||
so a message still arrives while she sits at her prompt.
|
||||
- Every VM is registered with the switch signal at its birth (idempotent; the Tripod and
|
||||
WIREBIND registrations stay) and unregistered when killed or reaped.
|
||||
- `sk_hermes_drain_checkpoint()` refuses, with "Kernel-Hermes: message held -- its VM is not the
|
||||
one running", any call not in the VM's own context: its interpreter running at the outermost
|
||||
text, or it is the VM switched in and not mid-line elsewhere. This is the test: it failed
|
||||
first, holding every relayed line (`logs/20261014-092558`), and never fires now.
|
||||
- A VM yielding from the top of its own loop stays LIVE; only a VM switched out mid-line is
|
||||
SWITCHED_OUT. Found by the test: with every yield SWITCHED_OUT, the console stopped relaying
|
||||
to an identity after its first message (it relays only to a LIVE one) and KILL would have
|
||||
refused every VM that had ever taken a message (`logs/20261014-095904`).
|
||||
|
||||
**A real defect found on the way, amd64 only:** `sk_vm_switch_prime()` (`arch/amd64/switch.S`)
|
||||
built a first-entry frame that left `rsp` a multiple of 16 at `sk_vm_switch_entry()`'s entry; the
|
||||
SysV ABI wants `rsp + 8` to be. Harmless while that function only switched back; a #GP (an
|
||||
aligned SSE store to the stack) the first time it ran the interpreter there
|
||||
(`logs/20261014-093823`). The frame is now 64 bytes with a null return address above the entry
|
||||
address. aarch64 (160) and riscv64 (208) frames were already 16-aligned. This may also be what
|
||||
stopped the 2026-09-14 attempt (`vm_interpret(self, "MSG-TICK")` in the same function, reverted
|
||||
after a stall never root-caused) -- not proven.
|
||||
|
||||
**`FABRIC-3.5.md` §XXXII.5's three build questions, as answered here:** (1) the payload waits in
|
||||
the receiver's kernel-Hermes queue and is run by the receiver on its own stack on its turn; (2)
|
||||
Hera's special case stays only in this sense -- her messages run at her own idle beat, which is
|
||||
her own context; (3) `g_mama_interpreting` and `g_idle_pump_active` stay, still guarding Hera's
|
||||
own drain.
|
||||
|
||||
**Verified.** A WIREBIND identity (`S" 00" USE`, then four plain lines: `1 2 + .`, an unknown
|
||||
word, `5 6 * .`, `7 8 + .`) receives and runs all four on its own stack -- `3`, the unknown-word
|
||||
error, `30`, `15` -- with nothing held and no fault, on amd64 (`logs/20261014-101933`), aarch64
|
||||
(`logs/20261014-102701`) and riscv64 (`logs/20261014-100948`). Five identity drives hot-plugged a
|
||||
second apart at the prompt all attach (their attach acknowledgements are messages to Hera)
|
||||
(`logs/20261014-102525`). Standard acceptance, committed disks: all three ISAs to `zuse@Hera`,
|
||||
POST 1052 tests passed, `PARITY:M7.1a ... hash=0x08873e0f44b7cb2a` unchanged, no unknown word
|
||||
(`logs/20261014-103248`, `-103409`, `-103616`). Superseded attempts, kept: `-092406` (wrong `USE`
|
||||
syntax), `-094908` (before the LIVE-on-yield fix, one line only).
|
||||
|
||||
Reference in New Issue
Block a user