refactor(wakes): epoch-stamp every registration-based wake; retire per-primitive wait seqs
The slot epoch is THE wait identity, so the hand-rolled per-primitive copies go away: channel loses cur_wait/next_wait_seq/timed_out, mutex loses Wait.seq and next_seq, TimerTarget::on_timeout takes the epoch. Registrations become (pid, epoch) — channel parked_receiver, mutex waiters, io fd waiters, Blocking io completions, sleep timers, joiner lists — and their wakers move to unpark_at. begin_wait is lock-free, so each primitive opens the wait inside the same critical section that publishes the registration. recv_timeout's wake-classification loop collapses: wakes are precise, so queue → Ok, senders==0 → Disconnected, else Timeout — the 'Defensive' re-register branch is now unreachable by protocol, not by audit. Same for Mutex::lock_timeout's one-shot park. End-state invariant, auditable in one sentence: the only wildcard wake is request_stop, which is terminal.
This commit is contained in:
+15
-15
@@ -124,11 +124,11 @@ use smarm::pid::Pid;
|
||||
use smarm::timer::{Reason, TimerTarget, Timers};
|
||||
|
||||
struct RecordingTarget {
|
||||
calls: Mutex<Vec<(Pid, u64)>>,
|
||||
calls: Mutex<Vec<(Pid, u32)>>,
|
||||
}
|
||||
impl TimerTarget for RecordingTarget {
|
||||
fn on_timeout(&self, pid: Pid, seq: u64) {
|
||||
self.calls.lock().unwrap().push((pid, seq));
|
||||
fn on_timeout(&self, pid: Pid, epoch: u32) {
|
||||
self.calls.lock().unwrap().push((pid, epoch));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,9 +137,9 @@ fn timers_pop_due_returns_entries_in_deadline_order() {
|
||||
let mut t = Timers::new();
|
||||
let now = Instant::now();
|
||||
// Insert out of order; pop_due should hand them back sorted by deadline.
|
||||
t.insert_sleep(now + Duration::from_millis(30), Pid::new(0, 0));
|
||||
t.insert_sleep(now + Duration::from_millis(10), Pid::new(1, 0));
|
||||
t.insert_sleep(now + Duration::from_millis(20), Pid::new(2, 0));
|
||||
t.insert_sleep(now + Duration::from_millis(30), Pid::new(0, 0), 1);
|
||||
t.insert_sleep(now + Duration::from_millis(10), Pid::new(1, 0), 1);
|
||||
t.insert_sleep(now + Duration::from_millis(20), Pid::new(2, 0), 1);
|
||||
|
||||
// Advance past all of them.
|
||||
let due = t.pop_due(now + Duration::from_millis(50));
|
||||
@@ -152,8 +152,8 @@ fn timers_pop_due_returns_entries_in_deadline_order() {
|
||||
fn timers_only_pop_entries_whose_deadline_has_passed() {
|
||||
let mut t = Timers::new();
|
||||
let now = Instant::now();
|
||||
t.insert_sleep(now + Duration::from_millis(5), Pid::new(0, 0));
|
||||
t.insert_sleep(now + Duration::from_millis(100), Pid::new(1, 0));
|
||||
t.insert_sleep(now + Duration::from_millis(5), Pid::new(0, 0), 1);
|
||||
t.insert_sleep(now + Duration::from_millis(100), Pid::new(1, 0), 1);
|
||||
|
||||
let due = t.pop_due(now + Duration::from_millis(20));
|
||||
assert_eq!(due.len(), 1);
|
||||
@@ -169,11 +169,11 @@ fn timers_mix_sleep_and_wait_timeout_reasons() {
|
||||
let target = Arc::new(RecordingTarget { calls: Mutex::new(Vec::new()) });
|
||||
let now = Instant::now();
|
||||
|
||||
t.insert_sleep(now + Duration::from_millis(5), Pid::new(0, 0));
|
||||
t.insert_sleep(now + Duration::from_millis(5), Pid::new(0, 0), 1);
|
||||
t.insert(
|
||||
now + Duration::from_millis(10),
|
||||
Pid::new(1, 0),
|
||||
Reason::WaitTimeout { target: target.clone(), wait_seq: 42 },
|
||||
Reason::WaitTimeout { target: target.clone(), epoch: 42 },
|
||||
);
|
||||
|
||||
let due = t.pop_due(now + Duration::from_millis(20));
|
||||
@@ -181,11 +181,11 @@ fn timers_mix_sleep_and_wait_timeout_reasons() {
|
||||
|
||||
// Order: Sleep (5ms) first, WaitTimeout (10ms) second.
|
||||
match &due[0].reason {
|
||||
Reason::Sleep => {}
|
||||
Reason::Sleep { .. } => {}
|
||||
_ => panic!("first entry should be a Sleep"),
|
||||
}
|
||||
match &due[1].reason {
|
||||
Reason::WaitTimeout { wait_seq, .. } => assert_eq!(*wait_seq, 42),
|
||||
Reason::WaitTimeout { epoch, .. } => assert_eq!(*epoch, 42),
|
||||
_ => panic!("second entry should be a WaitTimeout"),
|
||||
}
|
||||
}
|
||||
@@ -197,9 +197,9 @@ fn same_deadline_entries_pop_in_insertion_order() {
|
||||
let mut t = Timers::new();
|
||||
let now = Instant::now();
|
||||
let d = now + Duration::from_millis(10);
|
||||
t.insert_sleep(d, Pid::new(0, 0));
|
||||
t.insert_sleep(d, Pid::new(1, 0));
|
||||
t.insert_sleep(d, Pid::new(2, 0));
|
||||
t.insert_sleep(d, Pid::new(0, 0), 1);
|
||||
t.insert_sleep(d, Pid::new(1, 0), 1);
|
||||
t.insert_sleep(d, Pid::new(2, 0), 1);
|
||||
|
||||
let due = t.pop_due(now + Duration::from_millis(20));
|
||||
let pids: Vec<u32> = due.iter().map(|e| e.pid.index()).collect();
|
||||
|
||||
Reference in New Issue
Block a user