Stage 3 follow-on: fix stack-ownership corruption + DoE switch columns (FABRIC-3.md §XXVIII.1)
DoE CSV gained 6 switch-signal columns (switch_count_cumulative, switch_current_slot, switch_*_readiness, switch_ticks_since), and verifying them with a boot-time HB-ON probe surfaced a real livelock: the preemption checkpoint could fire inside a VM-EXEC-nested execute_colon_word() call and switch away from a stack it didn't own, parking a borrowed region of the caller's stack under the wrong VM's saved-context pointer. The trampoline bounce was the visible (safe) half of this; the corruption was the quiet half, live in every prior "clean" Stage 3 boot without ever showing up in the log. Fixed by gating the checkpoint on being at the outermost vm_interpret() call (g_vm_interpret_depth / sk_vm_at_outermost_interpret(), vm_core.c), per Bob's decision. Also fixed two related bugs found in the same pass: g_switch_back_to was a single global stale after first entry, now per-VM state (native_switch_back_to); note_switch_performed() fired on resume instead of switch-out, now called before the switch. Verified on all 3 architectures: steady log growth (no freeze), zero leaked QEMU processes, DoE columns internally consistent, Hermes/Artemis confirmed genuinely executing (not just trampoline-bouncing). Temporary HB-ON boot probe reverted after capture. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016UNhH1mhi52i6Qihh7ZV5S
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
986d042aa7
commit
862d7d9c48
@@ -46,6 +46,29 @@
|
||||
* 20. fleet_conserved uint32 — vm_physics_conserved() as 0/1: whether
|
||||
* |fleet_k_q48 - Q48_ONE| < VM_PHYSICS_EPSILON_Q48
|
||||
* at the moment this row was captured.
|
||||
* 21. switch_count_cumulative uint64 — Stage 3 preemptive-switch count, cumulative
|
||||
* since boot (capsule_vm_switch_signal.c).
|
||||
* 22. switch_current_slot uint32 — which registered switch-signal participant is
|
||||
* executing at this tick (0=Hera,1=Hermes,
|
||||
* 2=Artemis by current registration order;
|
||||
* 0xFFFFFFFF = none/unregistered at this moment).
|
||||
* 23. switch_hera_readiness uint32 — Hera's raw readiness accumulator (slot 0).
|
||||
* 24. switch_hermes_readiness uint32 — Hermes's raw readiness accumulator (slot 1).
|
||||
* 25. switch_artemis_readiness uint32 — Artemis's raw readiness accumulator (slot 2).
|
||||
* 26. switch_ticks_since uint32 — ticks elapsed since the last real switch
|
||||
* (capsule_vm_switch_signal.c); empirically
|
||||
* verifies the fixed 50-tick threshold under
|
||||
* real DoE load rather than assuming it.
|
||||
*
|
||||
* Columns 21-26 (FABRIC-3.md §XXVIII Stage 3 follow-on, 2026-09-13): added
|
||||
* alongside Stage 3's timer-driven preemptive context switching -- read-only
|
||||
* exposure of state the switch-signal module already tracked internally for its
|
||||
* own decision-making; no new measurement logic, just made observable. Slot
|
||||
* readiness columns are hardcoded to the 3 known Tripod slots (same convention
|
||||
* as columns 16-18) rather than a dynamic per-slot column set, for the same
|
||||
* reason: this is a logging schema for the currently-known fleet, not the
|
||||
* switch-signal mechanism itself (which stays slot-count-agnostic, headroom for
|
||||
* up to 8 participants -- see capsule_vm_switch_signal.h).
|
||||
*
|
||||
* Note: avg_word_heat and estimated_jitter_ns are stored as double in the
|
||||
* snapshot but the freestanding snprintf has no %%f support. avg_word_heat
|
||||
@@ -67,6 +90,7 @@
|
||||
#include "starkernel/timer.h"
|
||||
#include "starkernel/capsule_birth.h"
|
||||
#include "starkernel/capsule_vm_physics.h"
|
||||
#include "starkernel/capsule_vm_switch_signal.h" /* FABRIC-3.md §XXVIII Stage 3 follow-on */
|
||||
#include "freestanding/stdio.h"
|
||||
#include "word_registry.h"
|
||||
|
||||
@@ -83,7 +107,10 @@ static const char *doe_header =
|
||||
"window_width,actual_window_size,predicted_label_hits,jitter_bits,"
|
||||
"apic_ticks,time_trust_q48,variance_q48,vm_call_depth_max,"
|
||||
"hera_heat_q48,hermes_heat_q48,artemis_heat_q48,"
|
||||
"fleet_k_q48,fleet_conserved";
|
||||
"fleet_k_q48,fleet_conserved,"
|
||||
"switch_count_cumulative,switch_current_slot,"
|
||||
"switch_hera_readiness,switch_hermes_readiness,switch_artemis_readiness,"
|
||||
"switch_ticks_since";
|
||||
|
||||
/* Looks up a Tripod VM's fleet heat by name; 0 if not currently registered
|
||||
* (e.g. between KILL and rebirth). */
|
||||
@@ -133,9 +160,28 @@ void doe_log_tick_row(VM *vm, const HeartbeatTickSnapshot *snap)
|
||||
uint64_t fleet_k_q48 = vm_physics_fleet_heat_sum();
|
||||
unsigned fleet_conserved = vm_physics_conserved() ? 1u : 0u;
|
||||
|
||||
/* FABRIC-3.md §XXVIII Stage 3 follow-on (2026-09-13): switch-signal
|
||||
* exposure, looked up by name each tick (same convention as the heat
|
||||
* columns above -- registration order is not assumed fixed). */
|
||||
uint64_t switch_count = sk_vm_switch_signal_switch_count();
|
||||
int switch_slot = sk_vm_switch_signal_current_slot();
|
||||
unsigned switch_current_slot = (switch_slot >= 0) ? (unsigned)switch_slot : 0xFFFFFFFFu;
|
||||
uint32_t switch_ticks_since = sk_vm_switch_signal_ticks_since_switch();
|
||||
uint32_t hera_readiness = 0, hermes_readiness = 0, artemis_readiness = 0;
|
||||
{
|
||||
VMRegistryEntry e;
|
||||
if (capsule_vm_find_by_name_nocase("Hera", &e) == 0)
|
||||
hera_readiness = sk_vm_switch_signal_readiness_of(e.vm_id);
|
||||
if (capsule_vm_find_by_name_nocase("Hermes", &e) == 0)
|
||||
hermes_readiness = sk_vm_switch_signal_readiness_of(e.vm_id);
|
||||
if (capsule_vm_find_by_name_nocase("Artemis", &e) == 0)
|
||||
artemis_readiness = sk_vm_switch_signal_readiness_of(e.vm_id);
|
||||
}
|
||||
|
||||
char buf[DOE_BUF_SIZE];
|
||||
snprintf(buf, sizeof(buf),
|
||||
"%u,%llu,%llu,%u,%u,%u,%llu,%llu,%u,%u,%u,%llu,%llu,%llu,%llu,%u,%llu,%llu,%llu,%llu,%u",
|
||||
"%u,%llu,%llu,%u,%u,%u,%llu,%llu,%u,%u,%u,%llu,%llu,%llu,%llu,%u,%llu,%llu,%llu,%llu,%u,"
|
||||
"%llu,%u,%u,%u,%u,%u",
|
||||
snap->tick_number,
|
||||
(unsigned long long)snap->elapsed_ns,
|
||||
(unsigned long long)snap->tick_interval_ns,
|
||||
@@ -156,7 +202,13 @@ void doe_log_tick_row(VM *vm, const HeartbeatTickSnapshot *snap)
|
||||
(unsigned long long)hermes_heat_q48,
|
||||
(unsigned long long)artemis_heat_q48,
|
||||
(unsigned long long)fleet_k_q48,
|
||||
fleet_conserved);
|
||||
fleet_conserved,
|
||||
(unsigned long long)switch_count,
|
||||
switch_current_slot,
|
||||
hera_readiness,
|
||||
hermes_readiness,
|
||||
artemis_readiness,
|
||||
switch_ticks_since);
|
||||
|
||||
console_puts(DOE_PREFIX);
|
||||
console_puts(buf);
|
||||
|
||||
Reference in New Issue
Block a user