feat(runtime): phase 1 — peel timers/io/monitor-id out of SharedState; gate stop sentinel behind PREEMPTION_ENABLED
- next_monitor_id -> AtomicU64 on RuntimeInner - timers -> own Mutex<Timers>; io -> own Mutex<Option<IoThread>> (lock order: io-before-shared) - pending_closures Vec folded into Slot::pending_closure - termination check reads io liveness before shared; ordering argument documented - poison fix: check_cancelled() no longer fires while preemption is disabled, so a cancellation unwind can never poison a runtime/channel mutex - regression test: tests/poison_stop.rs - ROADMAP_v0.5.md added
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
//! Regression: request_stop racing an alloc-under-lock must not poison any
|
||||
//! runtime mutex. Before the fix, check_cancelled() fired regardless of
|
||||
//! PREEMPTION_ENABLED, so a sentinel unwind could trigger inside with_shared
|
||||
//! (which allocates: run_queue.push_back, waiters.push, etc), poisoning the
|
||||
//! shared mutex and cascading lock().unwrap() panics.
|
||||
|
||||
use smarm::runtime::{init, Config};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[test]
|
||||
fn stop_storm_does_not_poison_runtime() {
|
||||
let rt = init(Config::exact(4));
|
||||
let completed = Arc::new(AtomicUsize::new(0));
|
||||
let c = completed.clone();
|
||||
rt.run(move || {
|
||||
// Spawn many short actors that allocate + yield heavily (hammering
|
||||
// with_shared), and request_stop each one mid-flight from siblings.
|
||||
let mut handles = Vec::new();
|
||||
for _ in 0..200 {
|
||||
let h = smarm::spawn(|| {
|
||||
for _ in 0..50 {
|
||||
let _v: Vec<u8> = Vec::with_capacity(64); // alloc → maybe_preempt
|
||||
smarm::yield_now();
|
||||
}
|
||||
});
|
||||
handles.push(h);
|
||||
}
|
||||
// Cancel half of them; the others run to completion. If any lock got
|
||||
// poisoned the runtime would panic on a subsequent lock().unwrap().
|
||||
for (i, h) in handles.iter().enumerate() {
|
||||
if i % 2 == 0 {
|
||||
smarm::request_stop(h.pid());
|
||||
}
|
||||
}
|
||||
for h in handles {
|
||||
let _ = h.join();
|
||||
}
|
||||
c.fetch_add(1, Ordering::SeqCst);
|
||||
});
|
||||
assert_eq!(completed.load(Ordering::SeqCst), 1, "root completed cleanly");
|
||||
}
|
||||
Reference in New Issue
Block a user