use deloxide::{Condvar, Mutex as DMutex, RwLock as DRwLock, thread};
use std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
};
use std::time::Duration;
mod common;
use common::{DEADLOCK_TIMEOUT, expect_deadlock, start_detector};
#[test]
fn test_mixed_three_thread_deadlock_mutex_rwlock_condvar() {
let harness = start_detector();
let m1 = Arc::new(DMutex::new(()));
let m2 = Arc::new(DMutex::new(()));
let rw = Arc::new(DRwLock::new(()));
let cv = Arc::new(Condvar::new());
let ready = Arc::new(AtomicBool::new(false));
{
let m2 = Arc::clone(&m2);
let rw = Arc::clone(&rw);
let cv = Arc::clone(&cv);
let ready = Arc::clone(&ready);
thread::spawn(move || {
let mut g2 = m2.lock();
while !ready.load(Ordering::SeqCst) {
cv.wait(&mut g2);
}
let _w = rw.write();
let _ = &mut g2;
});
}
{
let rw = Arc::clone(&rw);
let m1 = Arc::clone(&m1);
thread::spawn(move || {
let _r = rw.read();
std::thread::sleep(Duration::from_millis(30));
let _m1 = m1.lock();
let _ = &_r;
});
}
{
let m1 = Arc::clone(&m1);
let m2 = Arc::clone(&m2);
let cv = Arc::clone(&cv);
let ready = Arc::clone(&ready);
thread::spawn(move || {
let _c = m1.lock();
std::thread::sleep(Duration::from_millis(20));
ready.store(true, Ordering::SeqCst);
cv.notify_one();
std::thread::sleep(Duration::from_millis(20));
let _m2 = m2.lock();
let _ = &_c;
});
}
let info = expect_deadlock(&harness, DEADLOCK_TIMEOUT);
assert_eq!(info.thread_cycle.len(), 3, "Expected 3-thread cycle");
}