Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 29 additions & 6 deletions src/ultra/mesg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,14 @@ mod tests {
let mut tstore = [0u8; 128];
let t = tstore.as_mut_ptr() as *mut std::os::raw::c_void;
let sender_key = t as usize;
crate::ultra::thread::HLXThreadCreate(t, 5, bs_sender, ptr::null_mut(), ptr::null_mut(), 10);
crate::ultra::thread::HLXThreadCreate(
t,
5,
bs_sender,
ptr::null_mut(),
ptr::null_mut(),
10,
);
crate::ultra::thread::HLXThreadStart(t);

// Deterministically wait until the sender has actually PARKED in the full+BLOCK branch
Expand All @@ -257,7 +264,10 @@ mod tests {
std::thread::sleep(std::time::Duration::from_millis(5));
}
assert!(parked, "BLOCK send never parked on the full queue");
assert!(!BS_SENT.load(Ordering::SeqCst), "a parked send must not have completed");
assert!(
!BS_SENT.load(Ordering::SeqCst),
"a parked send must not have completed"
);

// Free one slot. FIFO: 0x11 (head) drains first; 0x44 stays queued.
let (ret, m) = recv(key, 0);
Expand All @@ -271,14 +281,23 @@ mod tests {
}
std::thread::sleep(std::time::Duration::from_millis(5));
}
assert!(BS_SENT.load(Ordering::SeqCst), "parked sender never woke after a slot freed");
assert!(
BS_SENT.load(Ordering::SeqCst),
"parked sender never woke after a slot freed"
);

let (r1, m1) = recv(key, 0);
assert_eq!(r1, 0);
assert_eq!(m1, 0x44, "retained older message drains before the woken sender's");
assert_eq!(
m1, 0x44,
"retained older message drains before the woken sender's"
);
let (r2, m2) = recv(key, 0);
assert_eq!(r2, 0);
assert_eq!(m2, 0x22, "woken sender's message was tail-inserted, after 0x44");
assert_eq!(
m2, 0x22,
"woken sender's message was tail-inserted, after 0x44"
);

// Teardown: wait for the sender to retire so its stack-derived key leaves the registries.
for _ in 0..200 {
Expand Down Expand Up @@ -425,7 +444,11 @@ mod tests {
let key = qkey(&mut backing);
create(key, 8);
assert_eq!(send_coalescing(key, VI), 0);
assert_eq!(send_coalescing(key, VI), 0, "suppressed post still reports success");
assert_eq!(
send_coalescing(key, VI),
0,
"suppressed post still reports success"
);
assert_eq!(recv(key, 0), (0, VI));
assert_eq!(recv(key, 0), (-1, 0), "only one retrace was ever queued");
}
Expand Down
37 changes: 31 additions & 6 deletions src/ultra/sched.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ pub(crate) static TEST_YIELD_TIMEOUT_MS: std::sync::atomic::AtomicU64 =
std::sync::atomic::AtomicU64::new(2);
#[cfg(test)]
fn yield_wait_timeout() -> std::time::Duration {
std::time::Duration::from_millis(TEST_YIELD_TIMEOUT_MS.load(std::sync::atomic::Ordering::SeqCst))
std::time::Duration::from_millis(
TEST_YIELD_TIMEOUT_MS.load(std::sync::atomic::Ordering::SeqCst),
)
}
/// Test-only: times a thread has entered the sole-runnable wait, so a test can wait until the
/// caller is provably parked before injecting a wake.
Expand Down Expand Up @@ -379,7 +381,13 @@ mod tests {
// Nothing else at/above the caller's priority: the yield keeps the caller.
let mut m = HashMap::new();
m.insert(5usize, e(10));
m.insert(3usize, SchedEntry { pri: 100, ready: false }); // higher but blocked
m.insert(
3usize,
SchedEntry {
pri: 100,
ready: false,
},
); // higher but blocked
assert_eq!(pick_next_yield(&m, 5), Some(5));
}

Expand All @@ -394,6 +402,7 @@ mod tests {
assert_eq!(pick_next_yield(&m, 5), Some(6));
assert_eq!(pick_next_yield(&m, 6), Some(7));
assert_eq!(pick_next_yield(&m, 7), Some(5)); // wrap

// Contrast: the non-yield pick keeps the running thread on a tie.
assert_eq!(pick_next(&m, Some(5)), Some(5));
}
Expand Down Expand Up @@ -485,7 +494,10 @@ mod tests {
let before = s.inner.lock().unwrap().wake_gen;
wake(key);
let after = s.inner.lock().unwrap().wake_gen;
assert_ne!(before, after, "wake() must bump wake_gen to release a sole-runnable yielder");
assert_ne!(
before, after,
"wake() must bump wake_gen to release a sole-runnable yielder"
);
}

static RY_PEER_Q: AtomicUsize = AtomicUsize::new(0);
Expand Down Expand Up @@ -535,7 +547,12 @@ mod tests {
let pt = ps.as_mut_ptr() as *mut std::os::raw::c_void;
let peer_key = pt as usize;
crate::ultra::thread::HLXThreadCreate(
pt, 200, ry_peer, std::ptr::null_mut(), std::ptr::null_mut(), 100,
pt,
200,
ry_peer,
std::ptr::null_mut(),
std::ptr::null_mut(),
100,
);
crate::ultra::thread::HLXThreadStart(pt);

Expand All @@ -558,7 +575,12 @@ mod tests {
let ct = cs.as_mut_ptr() as *mut std::os::raw::c_void;
let caller_key = ct as usize;
crate::ultra::thread::HLXThreadCreate(
ct, 201, ry_caller, std::ptr::null_mut(), std::ptr::null_mut(), 10,
ct,
201,
ry_caller,
std::ptr::null_mut(),
std::ptr::null_mut(),
10,
);
crate::ultra::thread::HLXThreadStart(ct);

Expand All @@ -574,7 +596,10 @@ mod tests {
}
assert!(armed, "caller never entered the sole-wait branch");
// Armed + 10s timeout ⇒ it is provably parked in the condvar wait, not busy-completing.
assert!(!RY_CALLER_DONE.load(Ordering::SeqCst), "caller not blocked in the sole-wait");
assert!(
!RY_CALLER_DONE.load(Ordering::SeqCst),
"caller not blocked in the sole-wait"
);

// Tokenless waker: send() wakes the peer; the caller must be released by that wake, hand
// off to it, and finish — well within the ~1s budget (vs the 10s timeout).
Expand Down
Loading