Stage 3 follow-on: message-arrival eligibility hook + trampoline-blind switch-storm fix (FABRIC-3.md §XXVIII.2)
Build / build-amd64-iso (push) Canceled after 0s
Build / build-aarch64-iso (push) Canceled after 0s
Build / build-riscv64-img (push) Canceled after 0s

Implements the message-arrival eligibility signal FABRIC-3.md §XXVIII.1 left
open (has_work per-slot flag, set via new SWITCH-MARK-WORK primitive from
MSG-SEND) so an idle VM never becomes a switch target purely by waiting out
the readiness threshold.

Also root-causes and fixes a second, independent switch-storm: the tick's
"who is current" check used vm_log_attributed_vm(), which can't see a VM
parked in switch.c's own raw trampoline. Replaced with a dedicated
g_switch_current_vm tracked by the switch mechanism itself, and moved
target-slot eligibility reset to the switch decision point instead of
relying on ISR polling to observe a window that can be only a few
instructions wide.

Verified live on all 3 architectures: clean boot to zuse@Hera] ok>, live
cross-VM message dispatch, and (since a quiet log looks identical to a
livelocked storm once the DoE probe is gone) confirmed genuine REPL
liveness via QMP send-key + screendump on aarch64/riscv64, not log
inspection alone.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BWpNjdwPtFLuVLaAq44L9K
This commit is contained in:
Robert Allan James
2026-09-14 17:39:20 -04:00
co-authored by Claude Sonnet 5
parent 862d7d9c48
commit 66beae7fd4
29 changed files with 121129 additions and 338 deletions
+41
View File
@@ -55,6 +55,7 @@
#include "starkernel/capsule_vm_physics.h"
#include "starkernel/vm/vm_internal.h"
#include "starkernel/vm/stadium.h" /* item 4.2 -- STADIUM-* words */
#include "starkernel/capsule_vm_switch_signal.h" /* FABRIC-3.md §XXVIII Stage 3 follow-on -- SWITCH-MARK-WORK */
#include "starkernel/vm/stadium_words.h" /* item 4.2 -- stadium_words_resident_heat() */
#include "starkernel/repl.h"
#include "starkernel/capsule_generated.h"
@@ -785,6 +786,43 @@ static void mama_word_vm_exec(VM *vm)
/* Stack clean on exit */
}
/**
* @brief SWITCH-MARK-WORK ( name-caddr name-u -- )
* FABRIC-3.md §XXVIII Stage 3 follow-on (2026-09-14): message-arrival
* eligibility hook. Called from MSG-SEND (capsules/common/messaging.4th)
* every time a message is sent to a VM, so the Stage 3 switch signal can
* tell "has recently been sent something" apart from "has just been idle
* long enough" before ever selecting it as a switch target. Silently
* ignores a malformed or unknown name -- this fires on the hot path of
* every message send, not a user-facing command, so it must never error
* or spam the console.
*/
static void mama_word_switch_mark_work(VM *vm)
{
char name[VM_NAME_MAX];
cell_t u, caddr;
uint32_t i;
VMRegistryEntry entry;
if (vm->dsp < 2) { vm->error = 1; return; }
u = vm_pop(vm);
caddr = vm_pop(vm);
if (u <= 0 || (uint32_t)u >= VM_NAME_MAX) return;
{
const uint8_t *p = vm_ptr(vm, (vaddr_t)caddr);
if (!p) return;
for (i = 0; i < (uint32_t)u; i++) name[i] = (char)p[i];
name[u] = '\0';
}
if (capsule_vm_find_by_name_nocase(name, &entry) == 0) {
sk_vm_switch_signal_mark_work(entry.vm_id);
}
}
/**
* @brief VM-CALL ( cmd-caddr cmd-u vm-name-caddr vm-name-u -- n )
* Like VM-EXEC but pops one cell from the target VM's TOS and pushes
@@ -1653,6 +1691,7 @@ void register_mama_forth_words(VM *vm)
register_word(vm, "VM-PHYSICS-STATUS", mama_word_vm_physics_status);
register_word(vm, "VM-STEP", mama_word_vm_step);
register_word(vm, "VM-EXEC", mama_word_vm_exec);
register_word(vm, "SWITCH-MARK-WORK", mama_word_switch_mark_work);
register_word(vm, "VM-CALL", mama_word_vm_call);
register_word(vm, "VM-HEAT", mama_word_vm_heat);
/* FABRIC-3.md SXX: the 8 STADIUM-* primitives register_child_vm_words()
@@ -1711,6 +1750,7 @@ void register_mama_forth_words(VM *vm)
register_word(vm, "VM-PHYSICS-STATUS", mama_word_vm_physics_status);
register_word(vm, "VM-STEP", mama_word_vm_step);
register_word(vm, "VM-EXEC", mama_word_vm_exec);
register_word(vm, "SWITCH-MARK-WORK", mama_word_switch_mark_work);
register_word(vm, "VM-CALL", mama_word_vm_call);
register_word(vm, "VM-HEAT", mama_word_vm_heat);
/* FABRIC-3.md SXX: the 8 STADIUM-* primitives register_child_vm_words()
@@ -1946,6 +1986,7 @@ void register_child_vm_words(VM *vm)
register_word(vm, "STOP", mama_word_stop);
register_word(vm, "EXEC", mama_word_exec);
register_word(vm, "VM-EXEC", mama_word_vm_exec);
register_word(vm, "SWITCH-MARK-WORK", mama_word_switch_mark_work);
register_word(vm, "VM-CALL", mama_word_vm_call);
register_word(vm, "VM-HEAT", mama_word_vm_heat);
/* USE (FABRIC-2.md §F.24): not console-specific -- any VM can