From 594392a5aee54c27c4c4ce098c680a25107178e3 Mon Sep 17 00:00:00 2001 From: smarm-dev Date: Thu, 28 May 2026 05:50:18 +0000 Subject: [PATCH] examples: deterministic single-scheduler context-switch probe A minimal Config::exact(1) program with two actors doing a fixed number of yield_now() calls. No I/O/timers/channels, so the instruction stream stays centered on the naked-asm switch. Frame-pointer-friendly. Intended for single-threaded inspection under a debugger (e.g. llmdbg). --- examples/ctx_switch_probe.rs | 47 ++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 examples/ctx_switch_probe.rs diff --git a/examples/ctx_switch_probe.rs b/examples/ctx_switch_probe.rs new file mode 100644 index 0000000..4633693 --- /dev/null +++ b/examples/ctx_switch_probe.rs @@ -0,0 +1,47 @@ +//! A deliberately small, deterministic smarm program for inspecting the +//! naked-asm context switch under a debugger (llmdbg). +//! +//! Design goals that make it debugger-friendly: +//! - Exactly one scheduler thread (`Config::exact(1)`) so the whole run is +//! single-OS-threaded — llmdbg is single-threaded-debuggee only today. +//! - A known, small number of voluntary yields, so the number of +//! `switch_to_actor` / `switch_to_scheduler` transitions is predictable. +//! - Frame pointers preserved (see the [profile] note in how we build it), +//! so llmdbg's `finish()` and frame-pointer assumptions hold. +//! - No I/O, no timers, no channels — just the scheduler and the context +//! switch, to keep the instruction stream centered on the asm we care +//! about. +//! +//! Two actors each yield `N_YIELDS` times, printing a counter. Run normally +//! it just prints an interleaving. Run under llmdbg with breakpoints on +//! `smarm::context::switch_to_actor_asm` and +//! `smarm::context::switch_to_scheduler` to watch the stack pointer hand off +//! between the scheduler stack and each actor's mmap'd stack. + +use smarm::{init, Config}; + +const N_YIELDS: usize = 3; + +fn main() { + // Single scheduler thread: one OS thread, cooperative only. + let rt = init(Config::exact(1)); + rt.run(|| { + let a = smarm::spawn(|| { + for i in 0..N_YIELDS { + println!("actor A tick {i}"); + smarm::yield_now(); + } + println!("actor A done"); + }); + let b = smarm::spawn(|| { + for i in 0..N_YIELDS { + println!("actor B tick {i}"); + smarm::yield_now(); + } + println!("actor B done"); + }); + a.join().expect("A joined"); + b.join().expect("B joined"); + println!("root done"); + }); +}