Stage MC-0b: real kernel spinlocks; sf_mutex no longer a no-op (FABRIC-3.10.8 §3.2)

- New spinlock primitive (spinlock.h/.c): CAS on an owner word (core+1),
  interrupts masked while any lock is held (state kept in the per-core
  block, so release order doesn't matter). Recursion, release-not-held,
  held-at-switch and destroyed-while-held are counted and logged, never
  silent. Locks are no-ops until the boot core's block is installed
  (riscv64's monolithic early boot prints before sk_percpu_boot_init()).
- Kernel locks in a documented order: hermes, switch, registry, doe, log,
  console, heap, vmm, pmm. sf_mutex (dict_lock/tuning_lock) uses the same
  lock word.
- Hermes: public functions over *_locked internals; never held across the
  drain's vm_interpret_kind(); switch notifications after dropping the
  lock; event payload moved off static storage. Switch table and registry
  never call out while held (slot/entry copied under the lock).
- No lock crosses a switch: checked at context switch (leave, resume) and
  the idle point.
- Probe (removed): every lock balances on all three ISAs; 0 held at
  switch over 7.5M-51M checks; 0 recursions, 0 bad releases.
- Standard sequence on amd64/aarch64/riscv64: hashes and G byte-identical
  to MC-0a, MINT/WIREBIND/USE ok, conservation true, 0 idle growth.
- Block subsystem split out as MC-0b2 (Captain Bob's ruling).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-09-25 16:43:19 -04:00
co-authored by Claude Opus 5.5
parent 8409e376cf
commit 5bc7b4dee7
28 changed files with 56110 additions and 274 deletions
+9
View File
@@ -35,6 +35,7 @@
#include "starkernel/capsule_vm_switch_signal.h" /* FABRIC-3.8.md §3.13.3 -- the decision */
#include "starkernel/vm/bootstrap/sk_vm_bootstrap.h" /* sk_get_mama_vm() -- the idle root */
#include "starkernel/percpu.h" /* FABRIC-3.10.8 MC-0a -- this core's current VM */
#include "starkernel/spinlock.h" /* FABRIC-3.10.8 MC-0b -- no lock crosses a switch */
#include <stdint.h>
/* Arch-specific (switch.S in each arch dir). sk_vm_switch_prime() builds
@@ -226,6 +227,11 @@ void sk_vm_idle_point(int may_drain_self) {
VM *self = sk_percpu()->current_vm;
VM *next;
/* FABRIC-3.10.8 MC-0b: nothing is held on return to the idle point,
* which makes this the place to log any lock failure counted since. */
sk_lock_check_none_held("idle point");
sk_lock_report();
if (!self || self != (VM *)sk_get_mama_vm()) return;
if (self->frames.count != 0) return; /* inside a word (KEY/EXPECT): not idle */
@@ -280,7 +286,10 @@ int sk_vm_context_switch(VM *from, VM *to) {
sk_vm_switch_signal_note_parked(from->stadium_vm_id); /* §3.13.3 wait stamp */
sk_percpu()->current_vm = to;
/* FABRIC-3.10.8 MC-0b: no lock crosses a switch (spinlock.h). */
sk_lock_check_none_held("context switch, leaving");
sk_vm_switch_to(&from->native_stack_saved_sp, new_sp);
sk_lock_check_none_held("context switch, resumed");
/* Resumes here only once something later switches back to `from` --
* from `from`'s own point of view, this call simply took a while.