use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::mpsc::channel; use crate::sync::{Arc, Condvar, Mutex}; use crate::thread; use crate::time::Duration; #[test] fn smoke() { let c = Condvar::new(); c.notify_one(); c.notify_all(); } #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn notify_one() { let m = Arc::new(Mutex::new(())); let m2 = m.clone(); let c = Arc::new(Condvar::new()); let c2 = c.clone(); let g = m.lock().unwrap(); let _t = thread::spawn(move || { let _g = m2.lock().unwrap(); c2.notify_one(); }); let g = c.wait(g).unwrap(); drop(g); } #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn notify_all() { const N: usize = 10; let data = Arc::new((Mutex::new(0), Condvar::new())); let (tx, rx) = channel(); for _ in 0..N { let data = data.clone(); let tx = tx.clone(); thread::spawn(move || { let &(ref lock, ref cond) = &*data; let mut cnt = lock.lock().unwrap(); *cnt += 1; if *cnt == N { tx.send(()).unwrap(); } while *cnt != 0 { cnt = cond.wait(cnt).unwrap(); } tx.send(()).unwrap(); }); } drop(tx); let &(ref lock, ref cond) = &*data; rx.recv().unwrap(); let mut cnt = lock.lock().unwrap(); *cnt = 0; cond.notify_all(); drop(cnt); for _ in 0..N { rx.recv().unwrap(); } } #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn wait_while() { let pair = Arc::new((Mutex::new(false), Condvar::new())); let pair2 = pair.clone(); // Inside of our lock, spawn a new thread, and then wait for it to start. thread::spawn(move || { let &(ref lock, ref cvar) = &*pair2; let mut started = lock.lock().unwrap(); *started = true; // We notify the condvar that the value has changed. cvar.notify_one(); }); // Wait for the thread to start up. let &(ref lock, ref cvar) = &*pair; let guard = cvar.wait_while(lock.lock().unwrap(), |started| !*started); assert!(*guard.unwrap()); } #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn wait_timeout_wait() { let m = Arc::new(Mutex::new(())); let c = Arc::new(Condvar::new()); loop { let g = m.lock().unwrap(); let (_g, no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap(); // spurious wakeups mean this isn't necessarily true // so execute test again, if not timeout if !no_timeout.timed_out() { continue; } break; } } #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn wait_timeout_while_wait() { let m = Arc::new(Mutex::new(())); let c = Arc::new(Condvar::new()); let g = m.lock().unwrap(); let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(1), |_| true).unwrap(); // no spurious wakeups. ensure it timed-out assert!(wait.timed_out()); } #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn wait_timeout_while_instant_satisfy() { let m = Arc::new(Mutex::new(())); let c = Arc::new(Condvar::new()); let g = m.lock().unwrap(); let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(0), |_| false).unwrap(); // ensure it didn't time-out even if we were not given any time. assert!(!wait.timed_out()); } #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn wait_timeout_while_wake() { let pair = Arc::new((Mutex::new(false), Condvar::new())); let pair_copy = pair.clone(); let &(ref m, ref c) = &*pair; let g = m.lock().unwrap(); let _t = thread::spawn(move || { let &(ref lock, ref cvar) = &*pair_copy; let mut started = lock.lock().unwrap(); thread::sleep(Duration::from_millis(1)); *started = true; cvar.notify_one(); }); let (g2, wait) = c .wait_timeout_while(g, Duration::from_millis(u64::MAX), |&mut notified| !notified) .unwrap(); // ensure it didn't time-out even if we were not given any time. assert!(!wait.timed_out()); assert!(*g2); } #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn wait_timeout_wake() { let m = Arc::new(Mutex::new(())); let c = Arc::new(Condvar::new()); loop { let g = m.lock().unwrap(); let c2 = c.clone(); let m2 = m.clone(); let notified = Arc::new(AtomicBool::new(false)); let notified_copy = notified.clone(); let t = thread::spawn(move || { let _g = m2.lock().unwrap(); thread::sleep(Duration::from_millis(1)); notified_copy.store(true, Ordering::SeqCst); c2.notify_one(); }); let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u64::MAX)).unwrap(); assert!(!timeout_res.timed_out()); // spurious wakeups mean this isn't necessarily true // so execute test again, if not notified if !notified.load(Ordering::SeqCst) { t.join().unwrap(); continue; } drop(g); t.join().unwrap(); break; } }