#![allow(clippy::all)]
#[cfg(test)]
mod tests {
use crate::cx::Cx;
use crate::sync::mutex::Mutex;
use std::future::Future;
use std::pin::pin;
use std::sync::Arc;
use std::sync::atomic::{AtomicU32, Ordering};
use std::task::{Context, Poll, Waker};
fn poll_pinned_until_ready<T>(mut future: std::pin::Pin<&mut impl Future<Output = T>>) -> T {
let waker = Waker::noop();
let mut cx = Context::from_waker(waker);
loop {
match future.as_mut().poll(&mut cx) {
Poll::Ready(v) => return v,
Poll::Pending => std::thread::yield_now(),
}
}
}
#[test]
fn mutex_two_waiters_both_acquire_after_release() {
let lock = Arc::new(Mutex::new(0u32));
let acquired_count = Arc::new(AtomicU32::new(0));
let cx = Cx::for_testing();
let guard = poll_pinned_until_ready(pin!(lock.lock(&cx))).expect("initial lock failed");
let handles: Vec<_> = (0..2)
.map(|_| {
let lock = lock.clone();
let count = acquired_count.clone();
std::thread::spawn(move || {
let cx = Cx::for_testing();
let _g =
poll_pinned_until_ready(pin!(lock.lock(&cx))).expect("waiter lock failed");
count.fetch_add(1, Ordering::Relaxed);
})
})
.collect();
for _ in 0..10_000 {
if lock.waiters() == 2 {
break;
}
std::thread::yield_now();
}
assert_eq!(
lock.waiters(),
2,
"both waiters should be queued before release"
);
drop(guard);
for h in handles {
h.join().expect("waiter thread panicked");
}
assert_eq!(
acquired_count.load(Ordering::Relaxed),
2,
"both waiters should have acquired the mutex"
);
}
}