diff options
Diffstat (limited to 'ctr-std/src/sync/condvar.rs')
| -rw-r--r-- | ctr-std/src/sync/condvar.rs | 839 |
1 files changed, 0 insertions, 839 deletions
diff --git a/ctr-std/src/sync/condvar.rs b/ctr-std/src/sync/condvar.rs deleted file mode 100644 index 3014283..0000000 --- a/ctr-std/src/sync/condvar.rs +++ /dev/null @@ -1,839 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use fmt; -use sync::atomic::{AtomicUsize, Ordering}; -use sync::{mutex, MutexGuard, PoisonError}; -use sys_common::condvar as sys; -use sys_common::mutex as sys_mutex; -use sys_common::poison::{self, LockResult}; -use time::{Duration, Instant}; - -/// A type indicating whether a timed wait on a condition variable returned -/// due to a time out or not. -/// -/// It is returned by the [`wait_timeout`] method. -/// -/// [`wait_timeout`]: struct.Condvar.html#method.wait_timeout -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -#[stable(feature = "wait_timeout", since = "1.5.0")] -pub struct WaitTimeoutResult(bool); - -impl WaitTimeoutResult { - /// Returns whether the wait was known to have timed out. - /// - /// # Examples - /// - /// This example spawns a thread which will update the boolean value and - /// then wait 100 milliseconds before notifying the condvar. - /// - /// The main thread will wait with a timeout on the condvar and then leave - /// once the boolean has been updated and notified. - /// - /// ``` - /// use std::sync::{Arc, Mutex, Condvar}; - /// use std::thread; - /// use std::time::Duration; - /// - /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); - /// - /// thread::spawn(move|| { - /// let &(ref lock, ref cvar) = &*pair2; - /// - /// // Let's wait 20 milliseconds before notifying the condvar. - /// thread::sleep(Duration::from_millis(20)); - /// - /// let mut started = lock.lock().unwrap(); - /// // We update the boolean value. - /// *started = true; - /// cvar.notify_one(); - /// }); - /// - /// // Wait for the thread to start up. - /// let &(ref lock, ref cvar) = &*pair; - /// let mut started = lock.lock().unwrap(); - /// loop { - /// // Let's put a timeout on the condvar's wait. - /// let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap(); - /// // 10 milliseconds have passed, or maybe the value changed! - /// started = result.0; - /// if *started == true { - /// // We received the notification and the value has been updated, we can leave. - /// break - /// } - /// } - /// ``` - #[stable(feature = "wait_timeout", since = "1.5.0")] - pub fn timed_out(&self) -> bool { - self.0 - } -} - -/// A Condition Variable -/// -/// Condition variables represent the ability to block a thread such that it -/// consumes no CPU time while waiting for an event to occur. Condition -/// variables are typically associated with a boolean predicate (a condition) -/// and a mutex. The predicate is always verified inside of the mutex before -/// determining that a thread must block. -/// -/// Functions in this module will block the current **thread** of execution and -/// are bindings to system-provided condition variables where possible. Note -/// that this module places one additional restriction over the system condition -/// variables: each condvar can be used with precisely one mutex at runtime. Any -/// attempt to use multiple mutexes on the same condition variable will result -/// in a runtime panic. If this is not desired, then the unsafe primitives in -/// `sys` do not have this restriction but may result in undefined behavior. -/// -/// # Examples -/// -/// ``` -/// use std::sync::{Arc, Mutex, Condvar}; -/// use std::thread; -/// -/// 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 mut started = lock.lock().unwrap(); -/// while !*started { -/// started = cvar.wait(started).unwrap(); -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Condvar { - inner: Box<sys::Condvar>, - mutex: AtomicUsize, -} - -impl Condvar { - /// Creates a new condition variable which is ready to be waited on and - /// notified. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Condvar; - /// - /// let condvar = Condvar::new(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> Condvar { - let mut c = Condvar { - inner: box sys::Condvar::new(), - mutex: AtomicUsize::new(0), - }; - unsafe { - c.inner.init(); - } - c - } - - /// Blocks the current thread until this condition variable receives a - /// notification. - /// - /// This function will atomically unlock the mutex specified (represented by - /// `guard`) and block the current thread. This means that any calls - /// to [`notify_one`] or [`notify_all`] which happen logically after the - /// mutex is unlocked are candidates to wake this thread up. When this - /// function call returns, the lock specified will have been re-acquired. - /// - /// Note that this function is susceptible to spurious wakeups. Condition - /// variables normally have a boolean predicate associated with them, and - /// the predicate must always be checked each time this function returns to - /// protect against spurious wakeups. - /// - /// # Errors - /// - /// This function will return an error if the mutex being waited on is - /// poisoned when this thread re-acquires the lock. For more information, - /// see information about [poisoning] on the [`Mutex`] type. - /// - /// # Panics - /// - /// This function will [`panic!`] if it is used with more than one mutex - /// over time. Each condition variable is dynamically bound to exactly one - /// mutex to ensure defined behavior across platforms. If this functionality - /// is not desired, then unsafe primitives in `sys` are provided. - /// - /// [`notify_one`]: #method.notify_one - /// [`notify_all`]: #method.notify_all - /// [poisoning]: ../sync/struct.Mutex.html#poisoning - /// [`Mutex`]: ../sync/struct.Mutex.html - /// [`panic!`]: ../../std/macro.panic.html - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Mutex, Condvar}; - /// use std::thread; - /// - /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); - /// - /// 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 mut started = lock.lock().unwrap(); - /// // As long as the value inside the `Mutex` is false, we wait. - /// while !*started { - /// started = cvar.wait(started).unwrap(); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) - -> LockResult<MutexGuard<'a, T>> { - let poisoned = unsafe { - let lock = mutex::guard_lock(&guard); - self.verify(lock); - self.inner.wait(lock); - mutex::guard_poison(&guard).get() - }; - if poisoned { - Err(PoisonError::new(guard)) - } else { - Ok(guard) - } - } - - /// Blocks the current thread until this condition variable receives a - /// notification and the required condition is met. Spurious wakeups are - /// ignored and this function will only return once the condition has been - /// met. - /// - /// This function will atomically unlock the mutex specified (represented by - /// `guard`) and block the current thread. This means that any calls - /// to [`notify_one`] or [`notify_all`] which happen logically after the - /// mutex is unlocked are candidates to wake this thread up. When this - /// function call returns, the lock specified will have been re-acquired. - /// - /// # Errors - /// - /// This function will return an error if the mutex being waited on is - /// poisoned when this thread re-acquires the lock. For more information, - /// see information about [poisoning] on the [`Mutex`] type. - /// - /// [`notify_one`]: #method.notify_one - /// [`notify_all`]: #method.notify_all - /// [poisoning]: ../sync/struct.Mutex.html#poisoning - /// [`Mutex`]: ../sync/struct.Mutex.html - /// - /// # Examples - /// - /// ``` - /// #![feature(wait_until)] - /// - /// use std::sync::{Arc, Mutex, Condvar}; - /// use std::thread; - /// - /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); - /// - /// 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; - /// // As long as the value inside the `Mutex` is false, we wait. - /// let _guard = cvar.wait_until(lock.lock().unwrap(), |started| { *started }).unwrap(); - /// ``` - #[unstable(feature = "wait_until", issue = "47960")] - pub fn wait_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>, - mut condition: F) - -> LockResult<MutexGuard<'a, T>> - where F: FnMut(&mut T) -> bool { - while !condition(&mut *guard) { - guard = self.wait(guard)?; - } - Ok(guard) - } - - - /// Waits on this condition variable for a notification, timing out after a - /// specified duration. - /// - /// The semantics of this function are equivalent to [`wait`] - /// except that the thread will be blocked for roughly no longer - /// than `ms` milliseconds. This method should not be used for - /// precise timing due to anomalies such as preemption or platform - /// differences that may not cause the maximum amount of time - /// waited to be precisely `ms`. - /// - /// Note that the best effort is made to ensure that the time waited is - /// measured with a monotonic clock, and not affected by the changes made to - /// the system time. - /// - /// The returned boolean is `false` only if the timeout is known - /// to have elapsed. - /// - /// Like [`wait`], the lock specified will be re-acquired when this function - /// returns, regardless of whether the timeout elapsed or not. - /// - /// [`wait`]: #method.wait - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Mutex, Condvar}; - /// use std::thread; - /// - /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); - /// - /// 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 mut started = lock.lock().unwrap(); - /// // As long as the value inside the `Mutex` is false, we wait. - /// loop { - /// let result = cvar.wait_timeout_ms(started, 10).unwrap(); - /// // 10 milliseconds have passed, or maybe the value changed! - /// started = result.0; - /// if *started == true { - /// // We received the notification and the value has been updated, we can leave. - /// break - /// } - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::sync::Condvar::wait_timeout`")] - pub fn wait_timeout_ms<'a, T>(&self, guard: MutexGuard<'a, T>, ms: u32) - -> LockResult<(MutexGuard<'a, T>, bool)> { - let res = self.wait_timeout(guard, Duration::from_millis(ms as u64)); - poison::map_result(res, |(a, b)| { - (a, !b.timed_out()) - }) - } - - /// Waits on this condition variable for a notification, timing out after a - /// specified duration. - /// - /// The semantics of this function are equivalent to [`wait`] except that - /// the thread will be blocked for roughly no longer than `dur`. This - /// method should not be used for precise timing due to anomalies such as - /// preemption or platform differences that may not cause the maximum - /// amount of time waited to be precisely `dur`. - /// - /// Note that the best effort is made to ensure that the time waited is - /// measured with a monotonic clock, and not affected by the changes made to - /// the system time. This function is susceptible to spurious wakeups. - /// Condition variables normally have a boolean predicate associated with - /// them, and the predicate must always be checked each time this function - /// returns to protect against spurious wakeups. Additionally, it is - /// typically desirable for the time-out to not exceed some duration in - /// spite of spurious wakes, thus the sleep-duration is decremented by the - /// amount slept. Alternatively, use the `wait_timeout_until` method - /// to wait until a condition is met with a total time-out regardless - /// of spurious wakes. - /// - /// The returned [`WaitTimeoutResult`] value indicates if the timeout is - /// known to have elapsed. - /// - /// Like [`wait`], the lock specified will be re-acquired when this function - /// returns, regardless of whether the timeout elapsed or not. - /// - /// [`wait`]: #method.wait - /// [`wait_timeout_until`]: #method.wait_timeout_until - /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Mutex, Condvar}; - /// use std::thread; - /// use std::time::Duration; - /// - /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); - /// - /// 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 mut started = lock.lock().unwrap(); - /// // as long as the value inside the `Mutex` is false, we wait - /// loop { - /// let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap(); - /// // 10 milliseconds have passed, or maybe the value changed! - /// started = result.0; - /// if *started == true { - /// // We received the notification and the value has been updated, we can leave. - /// break - /// } - /// } - /// ``` - #[stable(feature = "wait_timeout", since = "1.5.0")] - pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>, - dur: Duration) - -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> { - let (poisoned, result) = unsafe { - let lock = mutex::guard_lock(&guard); - self.verify(lock); - let success = self.inner.wait_timeout(lock, dur); - (mutex::guard_poison(&guard).get(), WaitTimeoutResult(!success)) - }; - if poisoned { - Err(PoisonError::new((guard, result))) - } else { - Ok((guard, result)) - } - } - - /// Waits on this condition variable for a notification, timing out after a - /// specified duration. Spurious wakes will not cause this function to - /// return. - /// - /// The semantics of this function are equivalent to [`wait_until`] except - /// that the thread will be blocked for roughly no longer than `dur`. This - /// method should not be used for precise timing due to anomalies such as - /// preemption or platform differences that may not cause the maximum - /// amount of time waited to be precisely `dur`. - /// - /// Note that the best effort is made to ensure that the time waited is - /// measured with a monotonic clock, and not affected by the changes made to - /// the system time. - /// - /// The returned [`WaitTimeoutResult`] value indicates if the timeout is - /// known to have elapsed without the condition being met. - /// - /// Like [`wait_until`], the lock specified will be re-acquired when this - /// function returns, regardless of whether the timeout elapsed or not. - /// - /// [`wait_until`]: #method.wait_until - /// [`wait_timeout`]: #method.wait_timeout - /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html - /// - /// # Examples - /// - /// ``` - /// #![feature(wait_timeout_until)] - /// - /// use std::sync::{Arc, Mutex, Condvar}; - /// use std::thread; - /// use std::time::Duration; - /// - /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); - /// - /// 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 result = cvar.wait_timeout_until( - /// lock.lock().unwrap(), - /// Duration::from_millis(100), - /// |&mut started| started, - /// ).unwrap(); - /// if result.1.timed_out() { - /// // timed-out without the condition ever evaluating to true. - /// } - /// // access the locked mutex via result.0 - /// ``` - #[unstable(feature = "wait_timeout_until", issue = "47960")] - pub fn wait_timeout_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>, - dur: Duration, mut condition: F) - -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> - where F: FnMut(&mut T) -> bool { - let start = Instant::now(); - loop { - if condition(&mut *guard) { - return Ok((guard, WaitTimeoutResult(false))); - } - let timeout = match dur.checked_sub(start.elapsed()) { - Some(timeout) => timeout, - None => return Ok((guard, WaitTimeoutResult(true))), - }; - guard = self.wait_timeout(guard, timeout)?.0; - } - } - - /// Wakes up one blocked thread on this condvar. - /// - /// If there is a blocked thread on this condition variable, then it will - /// be woken up from its call to [`wait`] or [`wait_timeout`]. Calls to - /// `notify_one` are not buffered in any way. - /// - /// To wake up all threads, see [`notify_all`]. - /// - /// [`wait`]: #method.wait - /// [`wait_timeout`]: #method.wait_timeout - /// [`notify_all`]: #method.notify_all - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Mutex, Condvar}; - /// use std::thread; - /// - /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); - /// - /// 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 mut started = lock.lock().unwrap(); - /// // As long as the value inside the `Mutex` is false, we wait. - /// while !*started { - /// started = cvar.wait(started).unwrap(); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn notify_one(&self) { - unsafe { self.inner.notify_one() } - } - - /// Wakes up all blocked threads on this condvar. - /// - /// This method will ensure that any current waiters on the condition - /// variable are awoken. Calls to `notify_all()` are not buffered in any - /// way. - /// - /// To wake up only one thread, see [`notify_one`]. - /// - /// [`notify_one`]: #method.notify_one - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Mutex, Condvar}; - /// use std::thread; - /// - /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); - /// - /// 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_all(); - /// }); - /// - /// // Wait for the thread to start up. - /// let &(ref lock, ref cvar) = &*pair; - /// let mut started = lock.lock().unwrap(); - /// // As long as the value inside the `Mutex` is false, we wait. - /// while !*started { - /// started = cvar.wait(started).unwrap(); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn notify_all(&self) { - unsafe { self.inner.notify_all() } - } - - fn verify(&self, mutex: &sys_mutex::Mutex) { - let addr = mutex as *const _ as usize; - match self.mutex.compare_and_swap(0, addr, Ordering::SeqCst) { - // If we got out 0, then we have successfully bound the mutex to - // this cvar. - 0 => {} - - // If we get out a value that's the same as `addr`, then someone - // already beat us to the punch. - n if n == addr => {} - - // Anything else and we're using more than one mutex on this cvar, - // which is currently disallowed. - _ => panic!("attempted to use a condition variable with two \ - mutexes"), - } - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Condvar { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("Condvar { .. }") - } -} - -#[stable(feature = "condvar_default", since = "1.10.0")] -impl Default for Condvar { - /// Creates a `Condvar` which is ready to be waited on and notified. - fn default() -> Condvar { - Condvar::new() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Drop for Condvar { - fn drop(&mut self) { - unsafe { self.inner.destroy() } - } -} - -#[cfg(test)] -mod tests { - /// #![feature(wait_until)] - use sync::mpsc::channel; - use sync::{Condvar, Mutex, Arc}; - use sync::atomic::{AtomicBool, Ordering}; - use thread; - use time::Duration; - use u64; - - #[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_until() { - 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_until(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_until_wait() { - let m = Arc::new(Mutex::new(())); - let c = Arc::new(Condvar::new()); - - let g = m.lock().unwrap(); - let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(1), |_| { false }).unwrap(); - // no spurious wakeups. ensure it timed-out - assert!(wait.timed_out()); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_timeout_until_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_until(g, Duration::from_millis(0), |_| { true }).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_until_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_until(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; - } - } - - #[test] - #[should_panic] - #[cfg_attr(target_os = "emscripten", ignore)] - fn two_mutexes() { - 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().unwrap(); - let _t = thread::spawn(move|| { - let _g = m2.lock().unwrap(); - c2.notify_one(); - }); - g = c.wait(g).unwrap(); - drop(g); - - let m = Mutex::new(()); - let _ = c.wait(m.lock().unwrap()).unwrap(); - } -} |