aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/sync
diff options
context:
space:
mode:
authorFenrir <[email protected]>2018-04-14 20:02:05 -0600
committerFenrir <[email protected]>2018-04-21 16:35:01 -0600
commitb330206f5590d88a2f995321d2ea847ded951d1d (patch)
tree4fecd0ca00b754c494e96b13e9837db48de93109 /ctr-std/src/sync
parentMove more implementation details to `imp` module (diff)
downloadctru-rs-b330206f5590d88a2f995321d2ea847ded951d1d.tar.xz
ctru-rs-b330206f5590d88a2f995321d2ea847ded951d1d.zip
Update for Rust nightly 2018-04-19
Diffstat (limited to 'ctr-std/src/sync')
-rw-r--r--ctr-std/src/sync/condvar.rs222
-rw-r--r--ctr-std/src/sync/mod.rs2
-rw-r--r--ctr-std/src/sync/mpsc/mpsc_queue.rs3
-rw-r--r--ctr-std/src/sync/mpsc/spsc_queue.rs2
-rw-r--r--ctr-std/src/sync/rwlock.rs4
5 files changed, 223 insertions, 10 deletions
diff --git a/ctr-std/src/sync/condvar.rs b/ctr-std/src/sync/condvar.rs
index 5640217..3014283 100644
--- a/ctr-std/src/sync/condvar.rs
+++ b/ctr-std/src/sync/condvar.rs
@@ -14,7 +14,7 @@ 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;
+use time::{Duration, Instant};
/// A type indicating whether a timed wait on a condition variable returned
/// due to a time out or not.
@@ -47,11 +47,13 @@ impl WaitTimeoutResult {
///
/// 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;
- /// // Let's wait 20 milliseconds before notifying the condvar.
- /// thread::sleep(Duration::from_millis(20));
/// cvar.notify_one();
/// });
///
@@ -219,6 +221,64 @@ impl Condvar {
}
}
+ /// 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.
///
@@ -293,7 +353,15 @@ impl Condvar {
///
/// 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 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.
@@ -302,6 +370,7 @@ impl Condvar {
/// returns, regardless of whether the timeout elapsed or not.
///
/// [`wait`]: #method.wait
+ /// [`wait_timeout_until`]: #method.wait_timeout_until
/// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html
///
/// # Examples
@@ -353,6 +422,80 @@ impl Condvar {
}
}
+ /// 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
@@ -478,6 +621,7 @@ impl Drop for Condvar {
#[cfg(test)]
mod tests {
+ /// #![feature(wait_until)]
use sync::mpsc::channel;
use sync::{Condvar, Mutex, Arc};
use sync::atomic::{AtomicBool, Ordering};
@@ -548,6 +692,29 @@ mod tests {
#[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());
@@ -567,6 +734,53 @@ mod tests {
#[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());
diff --git a/ctr-std/src/sync/mod.rs b/ctr-std/src/sync/mod.rs
index 289b47b..642b284 100644
--- a/ctr-std/src/sync/mod.rs
+++ b/ctr-std/src/sync/mod.rs
@@ -18,7 +18,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
-pub use alloc::arc::{Arc, Weak};
+pub use alloc_crate::arc::{Arc, Weak};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::sync::atomic;
diff --git a/ctr-std/src/sync/mpsc/mpsc_queue.rs b/ctr-std/src/sync/mpsc/mpsc_queue.rs
index 296773d..df945ac 100644
--- a/ctr-std/src/sync/mpsc/mpsc_queue.rs
+++ b/ctr-std/src/sync/mpsc/mpsc_queue.rs
@@ -23,10 +23,9 @@
pub use self::PopResult::*;
-use alloc::boxed::Box;
use core::ptr;
use core::cell::UnsafeCell;
-
+use boxed::Box;
use sync::atomic::{AtomicPtr, Ordering};
/// A result of the `pop` function.
diff --git a/ctr-std/src/sync/mpsc/spsc_queue.rs b/ctr-std/src/sync/mpsc/spsc_queue.rs
index cc4be92..9482f69 100644
--- a/ctr-std/src/sync/mpsc/spsc_queue.rs
+++ b/ctr-std/src/sync/mpsc/spsc_queue.rs
@@ -16,7 +16,7 @@
// http://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue
-use alloc::boxed::Box;
+use boxed::Box;
use core::ptr;
use core::cell::UnsafeCell;
diff --git a/ctr-std/src/sync/rwlock.rs b/ctr-std/src/sync/rwlock.rs
index 2edf02e..f7fdedc 100644
--- a/ctr-std/src/sync/rwlock.rs
+++ b/ctr-std/src/sync/rwlock.rs
@@ -24,8 +24,8 @@ use sys_common::rwlock as sys;
/// typically allows for read-only access (shared access).
///
/// In comparison, a [`Mutex`] does not distinguish between readers or writers
-/// that aquire the lock, therefore blocking any threads waiting for the lock to
-/// become available. An `RwLock` will allow any number of readers to aquire the
+/// that acquire the lock, therefore blocking any threads waiting for the lock to
+/// become available. An `RwLock` will allow any number of readers to acquire the
/// lock as long as a writer is not holding the lock.
///
/// The priority policy of the lock is dependent on the underlying operating