89 lines
2.4 KiB
Rust
89 lines
2.4 KiB
Rust
//@ignore-target-windows: Concurrency on Windows is not supported yet.
|
|
// We are making scheduler assumptions here.
|
|
//@compile-flags: -Zmiri-strict-provenance -Zmiri-preemption-rate=0
|
|
|
|
use std::sync::{Arc, Condvar, Mutex, RwLock};
|
|
use std::thread;
|
|
|
|
fn check_conditional_variables_notify_all() {
|
|
let pair = Arc::new(((Mutex::new(())), Condvar::new()));
|
|
|
|
// Spawn threads and block them on the conditional variable.
|
|
let handles: Vec<_> = (0..5)
|
|
.map(|_| {
|
|
let pair2 = pair.clone();
|
|
thread::spawn(move || {
|
|
let (lock, cvar) = &*pair2;
|
|
let guard = lock.lock().unwrap();
|
|
// Block waiting on the conditional variable.
|
|
let _ = cvar.wait(guard).unwrap();
|
|
})
|
|
})
|
|
.inspect(|_| {
|
|
// Ensure the other threads all run and block on the `wait`.
|
|
thread::yield_now();
|
|
thread::yield_now();
|
|
})
|
|
.collect();
|
|
|
|
let (_, cvar) = &*pair;
|
|
// Unblock all threads.
|
|
cvar.notify_all();
|
|
|
|
for handle in handles {
|
|
handle.join().unwrap();
|
|
}
|
|
}
|
|
|
|
fn check_rwlock_unlock_bug1() {
|
|
// There was a bug where when un-read-locking an rwlock that still has other
|
|
// readers waiting, we'd accidentally also let a writer in.
|
|
// That caused an ICE.
|
|
let l = Arc::new(RwLock::new(0));
|
|
|
|
let r1 = l.read().unwrap();
|
|
let r2 = l.read().unwrap();
|
|
|
|
// Make a waiting writer.
|
|
let l2 = l.clone();
|
|
let t = thread::spawn(move || {
|
|
let mut w = l2.write().unwrap();
|
|
*w += 1;
|
|
});
|
|
thread::yield_now();
|
|
|
|
drop(r1);
|
|
assert_eq!(*r2, 0);
|
|
thread::yield_now();
|
|
thread::yield_now();
|
|
thread::yield_now();
|
|
assert_eq!(*r2, 0);
|
|
drop(r2);
|
|
t.join().unwrap();
|
|
}
|
|
|
|
fn check_rwlock_unlock_bug2() {
|
|
// There was a bug where when un-read-locking an rwlock by letting the last reader leaver,
|
|
// we'd forget to wake up a writer.
|
|
// That meant the writer thread could never run again.
|
|
let l = Arc::new(RwLock::new(0));
|
|
|
|
let r = l.read().unwrap();
|
|
|
|
// Make a waiting writer.
|
|
let l2 = l.clone();
|
|
let h = thread::spawn(move || {
|
|
let _w = l2.write().unwrap();
|
|
});
|
|
thread::yield_now();
|
|
|
|
drop(r);
|
|
h.join().unwrap();
|
|
}
|
|
|
|
fn main() {
|
|
check_conditional_variables_notify_all();
|
|
check_rwlock_unlock_bug1();
|
|
check_rwlock_unlock_bug2();
|
|
}
|