feat: SMP stage 2, lock-free fast paths (GetTime, GetProcessId, DebugPutchar, no-op Yield), storm checks yield equivalence
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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!(
|
||||
|
||||
Reference in New Issue
Block a user