diff options
| author | Stuart Cook <Zalathar@users.noreply.github.com> | 2025-08-30 20:29:06 +1000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-30 20:29:06 +1000 |
| commit | eda6dc928323fcd0ac1b51cea1aa79ab17e8519d (patch) | |
| tree | c6b973e6d858c85b47f0f3bdeeeeb7b4707fed18 /library/std/src | |
| parent | 6421031e5765cf9bae01edb5f0d6c1d2cc25a927 (diff) | |
| parent | d210ce7dac4acb7653d647c77d56c10068dda82c (diff) | |
| download | rust-eda6dc928323fcd0ac1b51cea1aa79ab17e8519d.tar.gz rust-eda6dc928323fcd0ac1b51cea1aa79ab17e8519d.zip | |
Rollup merge of #144651 - connortsui20:nonpoison_condvar, r=joboet
Implementation: `#[feature(nonpoison_condvar)]` Tracking Issue: https://github.com/rust-lang/rust/issues/134645 This PR continues the effort made in https://github.com/rust-lang/rust/pull/144022 by adding the implementation of `nonpoison::condvar`. Many of the changes here are similar to the changes made to implement `nonpoison::mutex`. There are two other changes here. The first is that the `Barrier` implementation is migrated to use the `nonpoison::Condvar` instead of the `poison` variant. The second (which might be subject to some discussion) is that `WaitTimeoutResult` is moved up to `mod.rs`, as both `condvar` variants need that type (and I do not know if there is a better place to put it now). ### Related PRs - `nonpoison_rwlock` implementation: https://github.com/rust-lang/rust/pull/144648 - `nonpoison_once` implementation: https://github.com/rust-lang/rust/pull/144653
Diffstat (limited to 'library/std/src')
| -rw-r--r-- | library/std/src/sync/barrier.rs | 8 | ||||
| -rw-r--r-- | library/std/src/sync/mod.rs | 65 | ||||
| -rw-r--r-- | library/std/src/sync/nonpoison.rs | 3 | ||||
| -rw-r--r-- | library/std/src/sync/nonpoison/condvar.rs | 448 | ||||
| -rw-r--r-- | library/std/src/sync/nonpoison/mutex.rs | 8 | ||||
| -rw-r--r-- | library/std/src/sync/poison.rs | 2 | ||||
| -rw-r--r-- | library/std/src/sync/poison/condvar.rs | 66 | ||||
| -rw-r--r-- | library/std/src/sync/poison/mutex.rs | 6 |
8 files changed, 530 insertions, 76 deletions
diff --git a/library/std/src/sync/barrier.rs b/library/std/src/sync/barrier.rs index 067ff66d9af..712ce03f90b 100644 --- a/library/std/src/sync/barrier.rs +++ b/library/std/src/sync/barrier.rs @@ -1,6 +1,5 @@ use crate::fmt; -// FIXME(nonpoison_mutex,nonpoison_condvar): switch to nonpoison versions once they are available -use crate::sync::{Condvar, Mutex}; +use crate::sync::nonpoison::{Condvar, Mutex}; /// A barrier enables multiple threads to synchronize the beginning /// of some computation. @@ -118,12 +117,11 @@ impl Barrier { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn wait(&self) -> BarrierWaitResult { - let mut lock = self.lock.lock().unwrap(); + let mut lock = self.lock.lock(); let local_gen = lock.generation_id; lock.count += 1; if lock.count < self.num_threads { - let _guard = - self.cvar.wait_while(lock, |state| local_gen == state.generation_id).unwrap(); + let _guard = self.cvar.wait_while(lock, |state| local_gen == state.generation_id); BarrierWaitResult(false) } else { lock.count = 0; diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 6ef3bf25cf6..97c04d07eaf 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -209,7 +209,7 @@ pub use self::poison::{LockResult, PoisonError}; #[doc(inline)] pub use self::poison::{ Mutex, MutexGuard, TryLockError, TryLockResult, - Condvar, WaitTimeoutResult, + Condvar, Once, OnceState, RwLock, RwLockReadGuard, RwLockWriteGuard, }; @@ -234,3 +234,66 @@ mod barrier; mod lazy_lock; mod once_lock; mod reentrant_lock; + +/// 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`]: Condvar::wait_timeout +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[stable(feature = "wait_timeout", since = "1.5.0")] +pub struct WaitTimeoutResult(bool); + +impl WaitTimeoutResult { + /// Returns `true` if the wait was known to have timed out. + /// + /// # Examples + /// + /// This example spawns a thread which will sleep 20 milliseconds before + /// updating a boolean value and then notifying the condvar. + /// + /// The main thread will wait with a 10 millisecond timeout on the condvar + /// and will leave the loop upon timeout. + /// + /// ``` + /// use std::sync::{Arc, Condvar, Mutex}; + /// use std::thread; + /// use std::time::Duration; + /// + /// let pair = Arc::new((Mutex::new(false), Condvar::new())); + /// let pair2 = Arc::clone(&pair); + /// + /// # let handle = + /// thread::spawn(move || { + /// let (lock, 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 (lock, cvar) = &*pair; + /// loop { + /// // Let's put a timeout on the condvar's wait. + /// let result = cvar.wait_timeout(lock.lock().unwrap(), Duration::from_millis(10)).unwrap(); + /// // 10 milliseconds have passed. + /// if result.1.timed_out() { + /// // timed out now and we can leave. + /// break + /// } + /// } + /// # // Prevent leaks for Miri. + /// # let _ = handle.join(); + /// ``` + #[must_use] + #[stable(feature = "wait_timeout", since = "1.5.0")] + pub fn timed_out(&self) -> bool { + self.0 + } +} diff --git a/library/std/src/sync/nonpoison.rs b/library/std/src/sync/nonpoison.rs index b3ae376e70d..ec3587263f4 100644 --- a/library/std/src/sync/nonpoison.rs +++ b/library/std/src/sync/nonpoison.rs @@ -29,6 +29,8 @@ impl fmt::Display for WouldBlock { } } +#[unstable(feature = "nonpoison_condvar", issue = "134645")] +pub use self::condvar::Condvar; #[unstable(feature = "mapped_lock_guards", issue = "117108")] pub use self::mutex::MappedMutexGuard; #[unstable(feature = "nonpoison_mutex", issue = "134645")] @@ -38,5 +40,6 @@ pub use self::rwlock::{MappedRwLockReadGuard, MappedRwLockWriteGuard}; #[unstable(feature = "nonpoison_rwlock", issue = "134645")] pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; +mod condvar; mod mutex; mod rwlock; diff --git a/library/std/src/sync/nonpoison/condvar.rs b/library/std/src/sync/nonpoison/condvar.rs new file mode 100644 index 00000000000..49afdd87818 --- /dev/null +++ b/library/std/src/sync/nonpoison/condvar.rs @@ -0,0 +1,448 @@ +use crate::fmt; +use crate::sync::WaitTimeoutResult; +use crate::sync::nonpoison::{MutexGuard, mutex}; +use crate::sys::sync as sys; +use crate::time::{Duration, Instant}; + +/// A Condition Variable +/// +/// For more information about condition variables, check out the documentation for the poisoning +/// variant of this type at [`poison::Condvar`]. +/// +/// # Examples +/// +/// Note that this `Condvar` does **not** propagate information about threads that panic while +/// holding a lock. If you need this functionality, see [`poison::Mutex`] and [`poison::Condvar`]. +/// +/// ``` +/// #![feature(nonpoison_mutex)] +/// #![feature(nonpoison_condvar)] +/// +/// use std::sync::nonpoison::{Mutex, Condvar}; +/// use std::sync::Arc; +/// use std::thread; +/// +/// let pair = Arc::new((Mutex::new(false), Condvar::new())); +/// let pair2 = Arc::clone(&pair); +/// +/// // Inside of our lock, spawn a new thread, and then wait for it to start. +/// thread::spawn(move || { +/// let (lock, 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 (lock, cvar) = &*pair; +/// let mut started = lock.lock(); +/// while !*started { +/// started = cvar.wait(started); +/// } +/// ``` +/// +/// [`poison::Mutex`]: crate::sync::poison::Mutex +/// [`poison::Condvar`]: crate::sync::poison::Condvar +#[unstable(feature = "nonpoison_condvar", issue = "134645")] +pub struct Condvar { + inner: sys::Condvar, +} + +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(); + /// ``` + #[unstable(feature = "nonpoison_condvar", issue = "134645")] + #[must_use] + #[inline] + pub const fn new() -> Condvar { + Condvar { inner: sys::Condvar::new() } + } + + /// 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. + /// + /// # Panics + /// + /// This function may [`panic!`] if it is used with more than one mutex + /// over time. + /// + /// [`notify_one`]: Self::notify_one + /// [`notify_all`]: Self::notify_all + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_mutex)] + /// #![feature(nonpoison_condvar)] + /// + /// use std::sync::nonpoison::{Mutex, Condvar}; + /// use std::sync::Arc; + /// use std::thread; + /// + /// let pair = Arc::new((Mutex::new(false), Condvar::new())); + /// let pair2 = Arc::clone(&pair); + /// + /// thread::spawn(move || { + /// let (lock, 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 (lock, cvar) = &*pair; + /// let mut started = lock.lock(); + /// // As long as the value inside the `Mutex<bool>` is `false`, we wait. + /// while !*started { + /// started = cvar.wait(started); + /// } + /// ``` + #[unstable(feature = "nonpoison_condvar", issue = "134645")] + pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> { + unsafe { + let lock = mutex::guard_lock(&guard); + self.inner.wait(lock); + } + guard + } + + /// Blocks the current thread until the provided condition becomes false. + /// + /// `condition` is checked immediately; if not met (returns `true`), this + /// will [`wait`] for the next notification then check again. This repeats + /// until `condition` returns `false`, in which case this function returns. + /// + /// 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. + /// + /// [`wait`]: Self::wait + /// [`notify_one`]: Self::notify_one + /// [`notify_all`]: Self::notify_all + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_mutex)] + /// #![feature(nonpoison_condvar)] + /// + /// use std::sync::nonpoison::{Mutex, Condvar}; + /// use std::sync::Arc; + /// use std::thread; + /// + /// let pair = Arc::new((Mutex::new(true), Condvar::new())); + /// let pair2 = Arc::clone(&pair); + /// + /// thread::spawn(move || { + /// let (lock, cvar) = &*pair2; + /// let mut pending = lock.lock(); + /// *pending = false; + /// // We notify the condvar that the value has changed. + /// cvar.notify_one(); + /// }); + /// + /// // Wait for the thread to start up. + /// let (lock, cvar) = &*pair; + /// // As long as the value inside the `Mutex<bool>` is `true`, we wait. + /// let _guard = cvar.wait_while(lock.lock(), |pending| { *pending }); + /// ``` + #[unstable(feature = "nonpoison_condvar", issue = "134645")] + pub fn wait_while<'a, T, F>( + &self, + mut guard: MutexGuard<'a, T>, + mut condition: F, + ) -> MutexGuard<'a, T> + where + F: FnMut(&mut T) -> bool, + { + while condition(&mut *guard) { + guard = self.wait(guard); + } + 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 `dur`. This + /// method should not be used for precise timing due to anomalies such as + /// preemption or platform differences that might 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 timeout 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_while` method + /// to wait with a timeout while a predicate is true. + /// + /// 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`]: Self::wait + /// [`wait_timeout_while`]: Self::wait_timeout_while + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_mutex)] + /// #![feature(nonpoison_condvar)] + /// + /// use std::sync::nonpoison::{Mutex, Condvar}; + /// use std::sync::Arc; + /// use std::thread; + /// use std::time::Duration; + /// + /// let pair = Arc::new((Mutex::new(false), Condvar::new())); + /// let pair2 = Arc::clone(&pair); + /// + /// thread::spawn(move || { + /// let (lock, 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 (lock, cvar) = &*pair; + /// let mut started = lock.lock(); + /// // as long as the value inside the `Mutex<bool>` is `false`, we wait + /// loop { + /// let result = cvar.wait_timeout(started, Duration::from_millis(10)); + /// // 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 + /// } + /// } + /// ``` + #[unstable(feature = "nonpoison_condvar", issue = "134645")] + pub fn wait_timeout<'a, T>( + &self, + guard: MutexGuard<'a, T>, + dur: Duration, + ) -> (MutexGuard<'a, T>, WaitTimeoutResult) { + let success = unsafe { + let lock = mutex::guard_lock(&guard); + self.inner.wait_timeout(lock, dur) + }; + (guard, WaitTimeoutResult(!success)) + } + + /// Waits on this condition variable for a notification, timing out after a + /// specified duration. + /// + /// The semantics of this function are equivalent to [`wait_while`] 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 might 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_while`], the lock specified will be re-acquired when this + /// function returns, regardless of whether the timeout elapsed or not. + /// + /// [`wait_while`]: Self::wait_while + /// [`wait_timeout`]: Self::wait_timeout + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_mutex)] + /// #![feature(nonpoison_condvar)] + /// + /// use std::sync::nonpoison::{Mutex, Condvar}; + /// use std::sync::Arc; + /// use std::thread; + /// use std::time::Duration; + /// + /// let pair = Arc::new((Mutex::new(true), Condvar::new())); + /// let pair2 = Arc::clone(&pair); + /// + /// thread::spawn(move || { + /// let (lock, cvar) = &*pair2; + /// let mut pending = lock.lock(); + /// *pending = false; + /// // We notify the condvar that the value has changed. + /// cvar.notify_one(); + /// }); + /// + /// // wait for the thread to start up + /// let (lock, cvar) = &*pair; + /// let result = cvar.wait_timeout_while( + /// lock.lock(), + /// Duration::from_millis(100), + /// |&mut pending| pending, + /// ); + /// if result.1.timed_out() { + /// // timed-out without the condition ever evaluating to false. + /// } + /// // access the locked mutex via result.0 + /// ``` + #[unstable(feature = "nonpoison_condvar", issue = "134645")] + pub fn wait_timeout_while<'a, T, F>( + &self, + mut guard: MutexGuard<'a, T>, + dur: Duration, + mut condition: F, + ) -> (MutexGuard<'a, T>, WaitTimeoutResult) + where + F: FnMut(&mut T) -> bool, + { + let start = Instant::now(); + loop { + if !condition(&mut *guard) { + return (guard, WaitTimeoutResult(false)); + } + let timeout = match dur.checked_sub(start.elapsed()) { + Some(timeout) => timeout, + None => return (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`]: Self::wait + /// [`wait_timeout`]: Self::wait_timeout + /// [`notify_all`]: Self::notify_all + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_mutex)] + /// #![feature(nonpoison_condvar)] + /// + /// use std::sync::nonpoison::{Mutex, Condvar}; + /// use std::sync::Arc; + /// use std::thread; + /// + /// let pair = Arc::new((Mutex::new(false), Condvar::new())); + /// let pair2 = Arc::clone(&pair); + /// + /// thread::spawn(move || { + /// let (lock, 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 (lock, cvar) = &*pair; + /// let mut started = lock.lock(); + /// // As long as the value inside the `Mutex<bool>` is `false`, we wait. + /// while !*started { + /// started = cvar.wait(started); + /// } + /// ``` + #[unstable(feature = "nonpoison_condvar", issue = "134645")] + pub fn notify_one(&self) { + 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`]: Self::notify_one + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_mutex)] + /// #![feature(nonpoison_condvar)] + /// + /// use std::sync::nonpoison::{Mutex, Condvar}; + /// use std::sync::Arc; + /// use std::thread; + /// + /// let pair = Arc::new((Mutex::new(false), Condvar::new())); + /// let pair2 = Arc::clone(&pair); + /// + /// thread::spawn(move || { + /// let (lock, cvar) = &*pair2; + /// let mut started = lock.lock(); + /// *started = true; + /// // We notify the condvar that the value has changed. + /// cvar.notify_all(); + /// }); + /// + /// // Wait for the thread to start up. + /// let (lock, cvar) = &*pair; + /// let mut started = lock.lock(); + /// // As long as the value inside the `Mutex<bool>` is `false`, we wait. + /// while !*started { + /// started = cvar.wait(started); + /// } + /// ``` + #[unstable(feature = "nonpoison_condvar", issue = "134645")] + pub fn notify_all(&self) { + self.inner.notify_all() + } +} + +#[unstable(feature = "nonpoison_condvar", issue = "134645")] +impl fmt::Debug for Condvar { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Condvar").finish_non_exhaustive() + } +} + +#[unstable(feature = "nonpoison_condvar", issue = "134645")] +impl Default for Condvar { + /// Creates a `Condvar` which is ready to be waited on and notified. + fn default() -> Condvar { + Condvar::new() + } +} diff --git a/library/std/src/sync/nonpoison/mutex.rs b/library/std/src/sync/nonpoison/mutex.rs index fd1e671d7a3..07430ce3a13 100644 --- a/library/std/src/sync/nonpoison/mutex.rs +++ b/library/std/src/sync/nonpoison/mutex.rs @@ -114,7 +114,6 @@ impl<T: ?Sized> !Send for MutexGuard<'_, T> {} #[unstable(feature = "nonpoison_mutex", issue = "134645")] unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {} -// FIXME(nonpoison_condvar): Use this link instead: [`Condvar`]: crate::sync::nonpoison::Condvar /// An RAII mutex guard returned by `MutexGuard::map`, which can point to a /// subfield of the protected data. When this structure is dropped (falls out /// of scope), the lock will be unlocked. @@ -131,7 +130,7 @@ unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {} /// /// [`map`]: MutexGuard::map /// [`filter_map`]: MutexGuard::filter_map -/// [`Condvar`]: crate::sync::Condvar +/// [`Condvar`]: crate::sync::nonpoison::Condvar #[must_use = "if unused the Mutex will immediately unlock"] #[must_not_suspend = "holding a MappedMutexGuard across suspend \ points can cause deadlocks, delays, \ @@ -458,6 +457,11 @@ impl<T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'_, T> { } } +/// For use in [`nonpoison::condvar`](super::condvar). +pub(super) fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { + &guard.lock.inner +} + impl<'a, T: ?Sized> MutexGuard<'a, T> { /// Makes a [`MappedMutexGuard`] for a component of the borrowed data, e.g. /// an enum variant. diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index 49a71b9ad10..17abdb9819b 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -61,7 +61,7 @@ //! then the lock will not be poisoned. #[stable(feature = "rust1", since = "1.0.0")] -pub use self::condvar::{Condvar, WaitTimeoutResult}; +pub use self::condvar::Condvar; #[unstable(feature = "mapped_lock_guards", issue = "117108")] pub use self::mutex::MappedMutexGuard; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/sync/poison/condvar.rs b/library/std/src/sync/poison/condvar.rs index 0e9d4233c65..5dc2b510f3a 100644 --- a/library/std/src/sync/poison/condvar.rs +++ b/library/std/src/sync/poison/condvar.rs @@ -1,73 +1,9 @@ use crate::fmt; +use crate::sync::WaitTimeoutResult; use crate::sync::poison::{self, LockResult, MutexGuard, PoisonError, mutex}; use crate::sys::sync as sys; use crate::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`]: Condvar::wait_timeout -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -#[stable(feature = "wait_timeout", since = "1.5.0")] -pub struct WaitTimeoutResult(bool); - -// FIXME(nonpoison_condvar): `WaitTimeoutResult` is actually poisoning-agnostic, it seems. -// Should we take advantage of this fact? -impl WaitTimeoutResult { - /// Returns `true` if the wait was known to have timed out. - /// - /// # Examples - /// - /// This example spawns a thread which will sleep 20 milliseconds before - /// updating a boolean value and then notifying the condvar. - /// - /// The main thread will wait with a 10 millisecond timeout on the condvar - /// and will leave the loop upon timeout. - /// - /// ``` - /// use std::sync::{Arc, Condvar, Mutex}; - /// use std::thread; - /// use std::time::Duration; - /// - /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = Arc::clone(&pair); - /// - /// # let handle = - /// thread::spawn(move || { - /// let (lock, 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 (lock, cvar) = &*pair; - /// loop { - /// // Let's put a timeout on the condvar's wait. - /// let result = cvar.wait_timeout(lock.lock().unwrap(), Duration::from_millis(10)).unwrap(); - /// // 10 milliseconds have passed. - /// if result.1.timed_out() { - /// // timed out now and we can leave. - /// break - /// } - /// } - /// # // Prevent leaks for Miri. - /// # let _ = handle.join(); - /// ``` - #[must_use] - #[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 diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 720c212c65c..7e9d920d92f 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -757,11 +757,13 @@ impl<T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'_, T> { } } -pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { +/// For use in [`nonpoison::condvar`](super::condvar). +pub(super) fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { &guard.lock.inner } -pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { +/// For use in [`nonpoison::condvar`](super::condvar). +pub(super) fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { &guard.lock.poison } |
