use std::{
sync::atomic::{AtomicU32, Ordering::Relaxed},
thread::sleep,
time::{Duration, Instant},
};
use wait_on_address::AtomicWait;
#[test]
fn wake_nothing() {
let a = AtomicU32::new(0);
a.notify_one();
a.notify_all();
}
#[test]
fn wait_unexpected() {
let t = Instant::now();
let a = AtomicU32::new(0);
a.wait(1);
assert!(t.elapsed().as_millis() < 100);
}
#[test]
fn wait_wake() {
let t = Instant::now();
let a = AtomicU32::new(0);
std::thread::scope(|s| {
s.spawn(|| {
sleep(Duration::from_millis(100));
a.store(1, Relaxed);
a.notify_one();
});
while a.load(Relaxed) == 0 {
a.wait(0);
}
assert_eq!(a.load(Relaxed), 1);
assert!((90..400).contains(&t.elapsed().as_millis()));
});
}
#[test]
fn wait_timeout() {
let a = AtomicU32::new(0);
a.wait_timeout(0, Duration::from_millis(1));
}
#[test]
fn stress_many_waiters_notify_all() {
use std::sync::Arc;
let a = Arc::new(AtomicU32::new(0));
let woke = Arc::new(AtomicU32::new(0));
let threads = 64;
std::thread::scope(|s| {
for _ in 0..threads {
let a = a.clone();
let woke = woke.clone();
s.spawn(move || {
while a.load(Relaxed) == 0 {
a.wait(0);
}
woke.fetch_add(1, Relaxed);
});
}
sleep(Duration::from_millis(50));
a.store(1, Relaxed);
a.notify_all();
});
assert_eq!(woke.load(Relaxed), threads);
}
#[test]
fn stress_ping_pong_many_iters() {
use std::sync::Arc;
let state = Arc::new(AtomicU32::new(0));
let iters = 5_000u32;
std::thread::scope(|s| {
let state_c = state.clone();
s.spawn(move || {
for _ in 0..iters {
while state_c.load(Relaxed) != 1 {
state_c.wait_timeout(0, Duration::from_millis(10));
}
state_c.store(0, Relaxed);
state_c.notify_one();
}
});
for _ in 0..iters {
state.store(1, Relaxed);
state.notify_one();
while state.load(Relaxed) != 0 {
state.wait_timeout(1, Duration::from_millis(10));
}
}
});
assert_eq!(state.load(Relaxed), 0);
}