feat: SMP stage 2, lock-free fast paths (GetTime, GetProcessId, DebugPutchar, no-op Yield), storm checks yield equivalence

This commit is contained in:
2026-10-27 01:07:57 +01:00
parent 2e665fd66e
commit 19aeabd86d
4 changed files with 154 additions and 3 deletions

View File

@@ -79,6 +79,15 @@ impl<P: Platform> Kernel<P> {
}
}
/// The highest priority waiting in `core`'s run queue.
pub fn highest_waiting(&self, core: CoreId) -> Option<Priority> {
self.scheduler.highest_waiting(core)
}
pub fn thread_priority(&self, tid: ThreadId) -> Option<Priority> {
self.threads.get(tid).ok().map(|t| t.priority())
}
/// What `core` should do after an IPI: keep running its thread, or
/// switch to a higher-priority one now waiting. When it has no thread
/// (it was idle, or its thread was destroyed) the caller picks the

View File

@@ -360,6 +360,22 @@ fn region_slots(k: &Kernel<MockPlatform>, pid: Option<ProcessId>) -> std::vec::V
.collect()
}
/// Every thread's state and queue, and every core's current thread.
fn scheduling_state(k: &Kernel<MockPlatform>) -> std::vec::Vec<std::string::String> {
let threads = k.live_threads().map(|t| {
format!(
"{t:?} {:?} {:?}",
k.thread_state_for_test(t),
k.scheduler.queued_on(t)
)
});
let cores = (0..k.scheduler.num_cores()).map(|c| {
let c = types::id::CoreId::from_raw(c);
format!("{c:?} {:?}", k.scheduler.current(c))
});
threads.chain(cores).collect()
}
/// What the adapter does whenever a core is left without a thread: run the
/// next one in its queue, if any.
fn resume(k: &mut Kernel<MockPlatform>, core: types::id::CoreId) {
@@ -483,7 +499,27 @@ fn storm(cores: u8) {
};
k.switch_to_thread_for_test(tid);
k.take_pending_result(tid);
// The adapter answers this Yield without the kernel lock; check
// that the kernel would indeed have changed nothing.
let yield_is_noop = nr == SYS_YIELD
&& k.current_thread() == Some(tid)
&& k.highest_waiting(core)
.is_none_or(|w| Some(w) < k.thread_priority(tid));
let before = yield_is_noop.then(|| scheduling_state(&k));
let out = k.handle_syscall(syscall);
if let Some(before) = before {
assert!(
matches!(
out,
crate::SyscallOutcome::Complete(crate::SyscallResult::Ok)
),
"seed {seed:#x} step {step}: fast-path Yield did not return Ok"
);
assert!(
before == scheduling_state(&k),
"seed {seed:#x} step {step}: fast-path Yield changed scheduling"
);
}
resume(&mut k, core);
executed += 1;
if !matches!(