feat: full runtime redesign (v0.6)
Complete rewrite with improved architecture & correctness: - src/runtime.rs: Simplified task scheduling with proper state transitions - src/scheduler.rs: Decoupled from runtime, pure task queue logic - src/io.rs, src/mutex.rs: Refactored for clarity & performance - New actor model framework (src/actor.rs, src/context.rs) - Channel primitives (src/channel.rs) & process IDs (src/pid.rs) - Preemption framework (src/preempt.rs) for fair timeslicing - Expanded benchmarks & tests (multi_scheduler, primes, runtime)
This commit is contained in:
99
tests/io.rs
Normal file
99
tests/io.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
//! Tests for `block_on_io` — running a blocking closure on a worker OS
|
||||
//! thread while the calling actor is parked.
|
||||
|
||||
use smarm::{block_on_io, run, spawn, yield_now};
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
fn block_on_io_returns_the_closures_value() {
|
||||
let captured: Arc<Mutex<Option<u64>>> = Arc::new(Mutex::new(None));
|
||||
let c = captured.clone();
|
||||
run(move || {
|
||||
let v: u64 = block_on_io(|| {
|
||||
// Burn a tiny bit of time so this actually crosses thread.
|
||||
std::thread::sleep(Duration::from_millis(5));
|
||||
42
|
||||
});
|
||||
*c.lock().unwrap() = Some(v);
|
||||
});
|
||||
assert_eq!(*captured.lock().unwrap(), Some(42));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn other_actors_run_while_block_on_io_is_in_flight() {
|
||||
// While actor A is parked in block_on_io, actor B should be able to
|
||||
// make progress.
|
||||
let order: Arc<Mutex<Vec<u8>>> = Arc::new(Mutex::new(Vec::new()));
|
||||
let oa = order.clone();
|
||||
let ob = order.clone();
|
||||
|
||||
run(move || {
|
||||
let a = spawn(move || {
|
||||
oa.lock().unwrap().push(1); // A starts first.
|
||||
block_on_io(|| {
|
||||
std::thread::sleep(Duration::from_millis(50));
|
||||
});
|
||||
oa.lock().unwrap().push(4); // A resumes last.
|
||||
});
|
||||
let b = spawn(move || {
|
||||
// Make sure A enters block_on_io first.
|
||||
yield_now();
|
||||
ob.lock().unwrap().push(2);
|
||||
yield_now();
|
||||
ob.lock().unwrap().push(3);
|
||||
});
|
||||
a.join().unwrap();
|
||||
b.join().unwrap();
|
||||
});
|
||||
|
||||
// Required interleaving: 1 (A starts) before 2,3 (B runs while A
|
||||
// is parked), and 4 (A resumes) after 2,3.
|
||||
let v = order.lock().unwrap();
|
||||
assert_eq!(v[0], 1, "log: {:?}", *v);
|
||||
assert_eq!(v[v.len() - 1], 4, "log: {:?}", *v);
|
||||
let pos_2 = v.iter().position(|&x| x == 2).unwrap();
|
||||
let pos_3 = v.iter().position(|&x| x == 3).unwrap();
|
||||
let pos_4 = v.iter().position(|&x| x == 4).unwrap();
|
||||
assert!(pos_2 < pos_4, "B's first step ran after A resumed: {:?}", *v);
|
||||
assert!(pos_3 < pos_4, "B's second step ran after A resumed: {:?}", *v);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn many_concurrent_block_on_io_calls_all_complete() {
|
||||
let counter = Arc::new(AtomicU32::new(0));
|
||||
let c = counter.clone();
|
||||
run(move || {
|
||||
let mut handles = Vec::new();
|
||||
for _ in 0..10 {
|
||||
let cc = c.clone();
|
||||
handles.push(spawn(move || {
|
||||
let n: u32 = block_on_io(|| {
|
||||
std::thread::sleep(Duration::from_millis(10));
|
||||
1
|
||||
});
|
||||
cc.fetch_add(n, Ordering::SeqCst);
|
||||
}));
|
||||
}
|
||||
for h in handles { h.join().unwrap(); }
|
||||
});
|
||||
assert_eq!(counter.load(Ordering::SeqCst), 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_on_io_panic_propagates_to_caller() {
|
||||
let saw_err = Arc::new(std::sync::atomic::AtomicBool::new(false));
|
||||
let s = saw_err.clone();
|
||||
run(move || {
|
||||
let h = spawn(move || {
|
||||
// The closure panics on the worker thread; that should
|
||||
// resurface as a panic in this actor.
|
||||
let _: () = block_on_io(|| panic!("boom on io thread"));
|
||||
});
|
||||
if h.join().is_err() {
|
||||
s.store(true, Ordering::SeqCst);
|
||||
}
|
||||
});
|
||||
assert!(saw_err.load(Ordering::SeqCst));
|
||||
}
|
||||
Reference in New Issue
Block a user