| use std::sync::Arc; | 
 | use std::sync::atomic::{AtomicBool, Ordering}; | 
 | use std::sync::mpsc::channel; | 
 | use std::thread; | 
 | use std::time::Duration; | 
 |  | 
 | use super::nonpoison_and_poison_unwrap_test; | 
 |  | 
 | nonpoison_and_poison_unwrap_test!( | 
 |     name: smoke, | 
 |     test_body: { | 
 |         use locks::Condvar; | 
 |  | 
 |         let c = Condvar::new(); | 
 |         c.notify_one(); | 
 |         c.notify_all(); | 
 |     } | 
 | ); | 
 |  | 
 | #[test] | 
 | #[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. | 
 | fn poison_notify_one() { | 
 |     use std::sync::poison::{Condvar, Mutex}; | 
 |  | 
 |     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(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. | 
 | fn nonpoison_notify_one() { | 
 |     use std::sync::nonpoison::{Condvar, Mutex}; | 
 |  | 
 |     let m = Arc::new(Mutex::new(())); | 
 |     let m2 = m.clone(); | 
 |     let c = Arc::new(Condvar::new()); | 
 |     let c2 = c.clone(); | 
 |  | 
 |     let mut g = m.lock(); | 
 |     let _t = thread::spawn(move || { | 
 |         let _g = m2.lock(); | 
 |         c2.notify_one(); | 
 |     }); | 
 |  | 
 |     c.wait(&mut g); | 
 |     drop(g); | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. | 
 | fn poison_notify_all() { | 
 |     use std::sync::poison::{Condvar, Mutex}; | 
 |  | 
 |     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(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. | 
 | fn nonpoison_notify_all() { | 
 |     use std::sync::nonpoison::{Condvar, Mutex}; | 
 |  | 
 |     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(); | 
 |             *cnt += 1; | 
 |             if *cnt == N { | 
 |                 tx.send(()).unwrap(); | 
 |             } | 
 |             while *cnt != 0 { | 
 |                 cond.wait(&mut cnt); | 
 |             } | 
 |             tx.send(()).unwrap(); | 
 |         }); | 
 |     } | 
 |     drop(tx); | 
 |  | 
 |     let &(ref lock, ref cond) = &*data; | 
 |     rx.recv().unwrap(); | 
 |     let mut cnt = lock.lock(); | 
 |     *cnt = 0; | 
 |     cond.notify_all(); | 
 |     drop(cnt); | 
 |  | 
 |     for _ in 0..N { | 
 |         rx.recv().unwrap(); | 
 |     } | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. | 
 | fn poison_test_mutex_arc_condvar() { | 
 |     use std::sync::poison::{Condvar, Mutex}; | 
 |  | 
 |     struct Packet<T>(Arc<(Mutex<T>, Condvar)>); | 
 |  | 
 |     let packet = Packet(Arc::new((Mutex::new(false), Condvar::new()))); | 
 |     let packet2 = Packet(packet.0.clone()); | 
 |  | 
 |     let (tx, rx) = channel(); | 
 |  | 
 |     let _t = thread::spawn(move || { | 
 |         // Wait until our parent has taken the lock. | 
 |         rx.recv().unwrap(); | 
 |         let &(ref lock, ref cvar) = &*packet2.0; | 
 |  | 
 |         // Set the data to `true` and wake up our parent. | 
 |         let mut guard = lock.lock().unwrap(); | 
 |         *guard = true; | 
 |         cvar.notify_one(); | 
 |     }); | 
 |  | 
 |     let &(ref lock, ref cvar) = &*packet.0; | 
 |     let mut guard = lock.lock().unwrap(); | 
 |     // Wake up our child. | 
 |     tx.send(()).unwrap(); | 
 |  | 
 |     // Wait until our child has set the data to `true`. | 
 |     assert!(!*guard); | 
 |     while !*guard { | 
 |         guard = cvar.wait(guard).unwrap(); | 
 |     } | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. | 
 | fn nonpoison_test_mutex_arc_condvar() { | 
 |     use std::sync::nonpoison::{Condvar, Mutex}; | 
 |  | 
 |     struct Packet<T>(Arc<(Mutex<T>, Condvar)>); | 
 |  | 
 |     let packet = Packet(Arc::new((Mutex::new(false), Condvar::new()))); | 
 |     let packet2 = Packet(packet.0.clone()); | 
 |  | 
 |     let (tx, rx) = channel(); | 
 |  | 
 |     let _t = thread::spawn(move || { | 
 |         // Wait until our parent has taken the lock. | 
 |         rx.recv().unwrap(); | 
 |         let &(ref lock, ref cvar) = &*packet2.0; | 
 |  | 
 |         // Set the data to `true` and wake up our parent. | 
 |         let mut guard = lock.lock(); | 
 |         *guard = true; | 
 |         cvar.notify_one(); | 
 |     }); | 
 |  | 
 |     let &(ref lock, ref cvar) = &*packet.0; | 
 |     let mut guard = lock.lock(); | 
 |     // Wake up our child. | 
 |     tx.send(()).unwrap(); | 
 |  | 
 |     // Wait until our child has set the data to `true`. | 
 |     assert!(!*guard); | 
 |     while !*guard { | 
 |         cvar.wait(&mut guard); | 
 |     } | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. | 
 | fn poison_wait_while() { | 
 |     use std::sync::poison::{Condvar, Mutex}; | 
 |  | 
 |     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).unwrap(); | 
 |     assert!(*guard); | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. | 
 | fn nonpoison_wait_while() { | 
 |     use std::sync::nonpoison::{Condvar, Mutex}; | 
 |  | 
 |     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(); | 
 |         *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 mut guard = lock.lock(); | 
 |     cvar.wait_while(&mut guard, |started| !*started); | 
 |     assert!(*guard); | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. | 
 | fn poison_wait_timeout_wait() { | 
 |     use std::sync::poison::{Condvar, Mutex}; | 
 |  | 
 |     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(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. | 
 | fn nonpoison_wait_timeout_wait() { | 
 |     use std::sync::nonpoison::{Condvar, Mutex}; | 
 |  | 
 |     let m = Arc::new(Mutex::new(())); | 
 |     let c = Arc::new(Condvar::new()); | 
 |  | 
 |     loop { | 
 |         let mut g = m.lock(); | 
 |         let no_timeout = c.wait_timeout(&mut g, Duration::from_millis(1)); | 
 |         // spurious wakeups mean this isn't necessarily true | 
 |         // so execute test again, if not timeout | 
 |         if !no_timeout.timed_out() { | 
 |             continue; | 
 |         } | 
 |  | 
 |         break; | 
 |     } | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. | 
 | fn poison_wait_timeout_while_wait() { | 
 |     use std::sync::poison::{Condvar, Mutex}; | 
 |  | 
 |     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(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. | 
 | fn nonpoison_wait_timeout_while_wait() { | 
 |     use std::sync::nonpoison::{Condvar, Mutex}; | 
 |  | 
 |     let m = Arc::new(Mutex::new(())); | 
 |     let c = Arc::new(Condvar::new()); | 
 |  | 
 |     let mut g = m.lock(); | 
 |     let wait = c.wait_timeout_while(&mut g, Duration::from_millis(1), |_| true); | 
 |     // no spurious wakeups. ensure it timed-out | 
 |     assert!(wait.timed_out()); | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. | 
 | fn poison_wait_timeout_while_instant_satisfy() { | 
 |     use std::sync::poison::{Condvar, Mutex}; | 
 |  | 
 |     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(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. | 
 | fn nonpoison_wait_timeout_while_instant_satisfy() { | 
 |     use std::sync::nonpoison::{Condvar, Mutex}; | 
 |  | 
 |     let m = Arc::new(Mutex::new(())); | 
 |     let c = Arc::new(Condvar::new()); | 
 |  | 
 |     let mut g = m.lock(); | 
 |     let wait = c.wait_timeout_while(&mut g, Duration::from_millis(0), |_| false); | 
 |     // ensure it didn't time-out even if we were not given any time. | 
 |     assert!(!wait.timed_out()); | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. | 
 | fn poison_wait_timeout_while_wake() { | 
 |     use std::sync::poison::{Condvar, Mutex}; | 
 |  | 
 |     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(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. | 
 | fn nonpoison_wait_timeout_while_wake() { | 
 |     use std::sync::nonpoison::{Condvar, Mutex}; | 
 |  | 
 |     let pair = Arc::new((Mutex::new(false), Condvar::new())); | 
 |     let pair_copy = pair.clone(); | 
 |  | 
 |     let &(ref m, ref c) = &*pair; | 
 |     let mut g = m.lock(); | 
 |     let _t = thread::spawn(move || { | 
 |         let &(ref lock, ref cvar) = &*pair_copy; | 
 |         let mut started = lock.lock(); | 
 |         thread::sleep(Duration::from_millis(1)); | 
 |         *started = true; | 
 |         cvar.notify_one(); | 
 |     }); | 
 |  | 
 |     let wait = | 
 |         c.wait_timeout_while(&mut g, Duration::from_millis(u64::MAX), |&mut notified| !notified); | 
 |     // ensure it didn't time-out even if we were not given any time. | 
 |     assert!(!wait.timed_out()); | 
 |     assert!(*g); | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. | 
 | fn poison_wait_timeout_wake() { | 
 |     use std::sync::poison::{Condvar, Mutex}; | 
 |  | 
 |     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::Relaxed); | 
 |             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::Relaxed) { | 
 |             t.join().unwrap(); | 
 |             continue; | 
 |         } | 
 |         drop(g); | 
 |  | 
 |         t.join().unwrap(); | 
 |  | 
 |         break; | 
 |     } | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. | 
 | fn nonpoison_wait_timeout_wake() { | 
 |     use std::sync::nonpoison::{Condvar, Mutex}; | 
 |  | 
 |     let m = Arc::new(Mutex::new(())); | 
 |     let c = Arc::new(Condvar::new()); | 
 |  | 
 |     loop { | 
 |         let mut g = m.lock(); | 
 |  | 
 |         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(); | 
 |             thread::sleep(Duration::from_millis(1)); | 
 |             notified_copy.store(true, Ordering::Relaxed); | 
 |             c2.notify_one(); | 
 |         }); | 
 |  | 
 |         let timeout_res = c.wait_timeout(&mut g, Duration::from_millis(u64::MAX)); | 
 |         assert!(!timeout_res.timed_out()); | 
 |         // spurious wakeups mean this isn't necessarily true | 
 |         // so execute test again, if not notified | 
 |         if !notified.load(Ordering::Relaxed) { | 
 |             t.join().unwrap(); | 
 |             continue; | 
 |         } | 
 |         drop(g); | 
 |  | 
 |         t.join().unwrap(); | 
 |  | 
 |         break; | 
 |     } | 
 | } | 
 |  | 
 | // Some platforms internally cast the timeout duration into nanoseconds. | 
 | // If they fail to consider overflow during the conversion (I'm looking | 
 | // at you, macOS), `wait_timeout` will return immediately and indicate a | 
 | // timeout for durations that are slightly longer than u64::MAX nanoseconds. | 
 | // `std` should guard against this by clamping the timeout. | 
 | // See #37440 for context. | 
 | #[test] | 
 | fn poison_timeout_nanoseconds() { | 
 |     use std::sync::poison::{Condvar, Mutex}; | 
 |  | 
 |     let sent = Mutex::new(false); | 
 |     let cond = Condvar::new(); | 
 |  | 
 |     thread::scope(|s| { | 
 |         s.spawn(|| { | 
 |             // Sleep so that the other thread has a chance to encounter the | 
 |             // timeout. | 
 |             thread::sleep(Duration::from_secs(2)); | 
 |             *sent.lock().unwrap() = true; | 
 |             cond.notify_all(); | 
 |         }); | 
 |  | 
 |         let mut guard = sent.lock().unwrap(); | 
 |         // Loop until `sent` is set by the thread to guard against spurious | 
 |         // wakeups. If the `wait_timeout` happens just before the signal by | 
 |         // the other thread, such a spurious wakeup might prevent the | 
 |         // miscalculated timeout from occurring, but this is basically just | 
 |         // a smoke test anyway. | 
 |         loop { | 
 |             if *guard { | 
 |                 break; | 
 |             } | 
 |  | 
 |             // If there is internal overflow, this call will return almost | 
 |             // immediately, before the other thread has reached the `notify_all`, | 
 |             // and indicate a timeout. | 
 |             let (g, res) = cond | 
 |                 .wait_timeout(guard, Duration::from_secs(u64::MAX.div_ceil(1_000_000_000))) | 
 |                 .unwrap(); | 
 |             assert!(!res.timed_out()); | 
 |             guard = g; | 
 |         } | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | fn nonpoison_timeout_nanoseconds() { | 
 |     use std::sync::nonpoison::{Condvar, Mutex}; | 
 |  | 
 |     let sent = Mutex::new(false); | 
 |     let cond = Condvar::new(); | 
 |  | 
 |     thread::scope(|s| { | 
 |         s.spawn(|| { | 
 |             // Sleep so that the other thread has a chance to encounter the | 
 |             // timeout. | 
 |             thread::sleep(Duration::from_secs(2)); | 
 |             sent.set(true); | 
 |             cond.notify_all(); | 
 |         }); | 
 |  | 
 |         let mut guard = sent.lock(); | 
 |         // Loop until `sent` is set by the thread to guard against spurious | 
 |         // wakeups. If the `wait_timeout` happens just before the signal by | 
 |         // the other thread, such a spurious wakeup might prevent the | 
 |         // miscalculated timeout from occurring, but this is basically just | 
 |         // a smoke test anyway. | 
 |         loop { | 
 |             if *guard { | 
 |                 break; | 
 |             } | 
 |  | 
 |             // If there is internal overflow, this call will return almost | 
 |             // immediately, before the other thread has reached the `notify_all`, | 
 |             // and indicate a timeout. | 
 |             let res = cond | 
 |                 .wait_timeout(&mut guard, Duration::from_secs(u64::MAX.div_ceil(1_000_000_000))); | 
 |             assert!(!res.timed_out()); | 
 |         } | 
 |     }) | 
 | } | 
 |  | 
 | #[test] | 
 | #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] | 
 | fn test_arc_condvar_poison() { | 
 |     use std::sync::poison::{Condvar, Mutex}; | 
 |  | 
 |     struct Packet<T>(Arc<(Mutex<T>, Condvar)>); | 
 |  | 
 |     let packet = Packet(Arc::new((Mutex::new(1), Condvar::new()))); | 
 |     let packet2 = Packet(packet.0.clone()); | 
 |     let (tx, rx) = channel(); | 
 |  | 
 |     let _t = thread::spawn(move || -> () { | 
 |         rx.recv().unwrap(); | 
 |         let &(ref lock, ref cvar) = &*packet2.0; | 
 |         let _g = lock.lock().unwrap(); | 
 |         cvar.notify_one(); | 
 |         // Parent should fail when it wakes up. | 
 |         panic!(); | 
 |     }); | 
 |  | 
 |     let &(ref lock, ref cvar) = &*packet.0; | 
 |     let mut lock = lock.lock().unwrap(); | 
 |     tx.send(()).unwrap(); | 
 |     while *lock == 1 { | 
 |         match cvar.wait(lock) { | 
 |             Ok(l) => { | 
 |                 lock = l; | 
 |                 assert_eq!(*lock, 1); | 
 |             } | 
 |             Err(..) => break, | 
 |         } | 
 |     } | 
 | } |