diff options
Diffstat (limited to 'src/libstd/sync')
| -rw-r--r-- | src/libstd/sync/condvar.rs | 368 | ||||
| -rw-r--r-- | src/libstd/sync/mod.rs | 14 | ||||
| -rw-r--r-- | src/libstd/sync/mutex.rs | 219 | ||||
| -rw-r--r-- | src/libstd/sync/rwlock.rs | 249 |
4 files changed, 170 insertions, 680 deletions
diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index bf4b119a0b6..3c52ebc72f2 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -15,7 +15,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::{Instant, Duration}; +use time::Duration; /// A type indicating whether a timed wait on a condition variable returned /// due to a time out or not. @@ -72,59 +72,19 @@ impl WaitTimeoutResult { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -pub struct Condvar { inner: Box<StaticCondvar> } - -/// Statically allocated condition variables. -/// -/// This structure is identical to `Condvar` except that it is suitable for use -/// in static initializers for other structures. -/// -/// # Examples -/// -/// ``` -/// #![feature(static_condvar)] -/// -/// use std::sync::{StaticCondvar, CONDVAR_INIT}; -/// -/// static CVAR: StaticCondvar = CONDVAR_INIT; -/// ``` -#[unstable(feature = "static_condvar", - reason = "may be merged with Condvar in the future", - issue = "27717")] -#[rustc_deprecated(since = "1.10.0", - reason = "the lazy-static crate suffices for static sync \ - primitives and eventually this type shouldn't \ - be necessary as `Condvar::new` in a static should \ - suffice")] -pub struct StaticCondvar { - inner: sys::Condvar, +pub struct Condvar { + inner: Box<sys::Condvar>, mutex: AtomicUsize, } -/// Constant initializer for a statically allocated condition variable. -#[unstable(feature = "static_condvar", - reason = "may be merged with Condvar in the future", - issue = "27717")] -#[rustc_deprecated(since = "1.10.0", - reason = "the lazy-static crate suffices for static sync \ - primitives and eventually this type shouldn't \ - be necessary as `Condvar::new` in a static should \ - suffice")] -#[allow(deprecated)] -pub const CONDVAR_INIT: StaticCondvar = StaticCondvar::new(); - -#[allow(deprecated)] impl Condvar { /// Creates a new condition variable which is ready to be waited on and /// notified. #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> Condvar { Condvar { - inner: box StaticCondvar { - inner: sys::Condvar::new(), - mutex: AtomicUsize::new(0), - } + inner: box sys::Condvar::new(), + mutex: AtomicUsize::new(0), } } @@ -157,9 +117,16 @@ impl Condvar { #[stable(feature = "rust1", since = "1.0.0")] pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> LockResult<MutexGuard<'a, T>> { - unsafe { - let me: &'static Condvar = &*(self as *const _); - me.inner.wait(guard) + 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) } } @@ -206,9 +173,16 @@ impl Condvar { pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>, dur: Duration) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> { - unsafe { - let me: &'static Condvar = &*(self as *const _); - me.inner.wait_timeout(guard, dur) + 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)) } } @@ -220,7 +194,9 @@ impl Condvar { /// /// To wake up all threads, see `notify_all()`. #[stable(feature = "rust1", since = "1.0.0")] - pub fn notify_one(&self) { unsafe { self.inner.inner.notify_one() } } + pub fn notify_one(&self) { + unsafe { self.inner.notify_one() } + } /// Wakes up all blocked threads on this condvar. /// @@ -230,169 +206,8 @@ impl Condvar { /// /// To wake up only one thread, see `notify_one()`. #[stable(feature = "rust1", since = "1.0.0")] - pub fn notify_all(&self) { unsafe { self.inner.inner.notify_all() } } -} - -#[stable(feature = "condvar_default", since = "1.9.0")] -impl Default for Condvar { - fn default() -> Condvar { - Condvar::new() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -impl Drop for Condvar { - fn drop(&mut self) { - unsafe { self.inner.inner.destroy() } - } -} - -#[rustc_deprecated(since = "1.10.0", - reason = "the lazy-static crate suffices for static sync \ - primitives and eventually this type shouldn't \ - be necessary as `Condvar::new` in a static should \ - suffice")] -#[unstable(feature = "static_condvar", - reason = "may be merged with Condvar in the future", - issue = "27717")] -#[allow(deprecated)] -impl StaticCondvar { - /// Creates a new condition variable - #[unstable(feature = "static_condvar", - reason = "may be merged with Condvar in the future", - issue = "27717")] - pub const fn new() -> StaticCondvar { - StaticCondvar { - inner: sys::Condvar::new(), - mutex: AtomicUsize::new(0), - } - } - - /// Blocks the current thread until this condition variable receives a - /// notification. - /// - /// See `Condvar::wait`. - #[unstable(feature = "static_condvar", - reason = "may be merged with Condvar in the future", - issue = "27717")] - pub fn wait<'a, T>(&'static 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) - } - } - - /// Waits on this condition variable for a notification, timing out after a - /// specified duration. - /// - /// See `Condvar::wait_timeout`. - #[unstable(feature = "static_condvar", - reason = "may be merged with Condvar in the future", - issue = "27717")] - pub fn wait_timeout<'a, T>(&'static self, - guard: MutexGuard<'a, T>, - timeout: 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, timeout); - (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. - /// - /// The implementation will repeatedly wait while the duration has not - /// passed and the function returns `false`. - /// - /// See `Condvar::wait_timeout_with`. - #[unstable(feature = "static_condvar", - reason = "may be merged with Condvar in the future", - issue = "27717")] - pub fn wait_timeout_with<'a, T, F>(&'static self, - guard: MutexGuard<'a, T>, - dur: Duration, - mut f: F) - -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> - where F: FnMut(LockResult<&mut T>) -> bool { - // This could be made more efficient by pushing the implementation into - // sys::condvar - let start = Instant::now(); - let mut guard_result: LockResult<MutexGuard<'a, T>> = Ok(guard); - while !f(guard_result - .as_mut() - .map(|g| &mut **g) - .map_err(|e| PoisonError::new(&mut **e.get_mut()))) { - let consumed = start.elapsed(); - let guard = guard_result.unwrap_or_else(|e| e.into_inner()); - let (new_guard_result, timed_out) = if consumed > dur { - (Ok(guard), WaitTimeoutResult(true)) - } else { - match self.wait_timeout(guard, dur - consumed) { - Ok((new_guard, timed_out)) => (Ok(new_guard), timed_out), - Err(err) => { - let (new_guard, no_timeout) = err.into_inner(); - (Err(PoisonError::new(new_guard)), no_timeout) - } - } - }; - guard_result = new_guard_result; - if timed_out.timed_out() { - let result = f(guard_result - .as_mut() - .map(|g| &mut **g) - .map_err(|e| PoisonError::new(&mut **e.get_mut()))); - let result = WaitTimeoutResult(!result); - return poison::map_result(guard_result, |g| (g, result)); - } - } - - poison::map_result(guard_result, |g| (g, WaitTimeoutResult(false))) - } - - /// Wakes up one blocked thread on this condvar. - /// - /// See `Condvar::notify_one`. - #[unstable(feature = "static_condvar", - reason = "may be merged with Condvar in the future", - issue = "27717")] - pub fn notify_one(&'static self) { unsafe { self.inner.notify_one() } } - - /// Wakes up all blocked threads on this condvar. - /// - /// See `Condvar::notify_all`. - #[unstable(feature = "static_condvar", - reason = "may be merged with Condvar in the future", - issue = "27717")] - pub fn notify_all(&'static self) { unsafe { self.inner.notify_all() } } - - /// Deallocates all resources associated with this static condvar. - /// - /// This method is unsafe to call as there is no guarantee that there are no - /// active users of the condvar, and this also doesn't prevent any future - /// users of the condvar. This method is required to be called to not leak - /// memory on all platforms. - #[unstable(feature = "static_condvar", - reason = "may be merged with Condvar in the future", - issue = "27717")] - pub unsafe fn destroy(&'static self) { - self.inner.destroy() + pub fn notify_all(&self) { + unsafe { self.inner.notify_all() } } fn verify(&self, mutex: &sys_mutex::Mutex) { @@ -414,15 +229,26 @@ impl StaticCondvar { } } +#[stable(feature = "condvar_default", since = "1.9.0")] +impl Default for Condvar { + 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)] -#[allow(deprecated)] mod tests { use prelude::v1::*; - use super::StaticCondvar; use sync::mpsc::channel; - use sync::{StaticMutex, Condvar, Mutex, Arc}; - use sync::atomic::{AtomicUsize, Ordering}; + use sync::{Condvar, Mutex, Arc}; use thread; use time::Duration; use u32; @@ -435,26 +261,19 @@ mod tests { } #[test] - fn static_smoke() { - static C: StaticCondvar = StaticCondvar::new(); - C.notify_one(); - C.notify_all(); - unsafe { C.destroy(); } - } - - #[test] fn notify_one() { - static C: StaticCondvar = StaticCondvar::new(); - static M: StaticMutex = StaticMutex::new(); + 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 g = m.lock().unwrap(); let _t = thread::spawn(move|| { - let _g = M.lock().unwrap(); - C.notify_one(); + let _g = m2.lock().unwrap(); + c2.notify_one(); }); - let g = C.wait(g).unwrap(); + let g = c.wait(g).unwrap(); drop(g); - unsafe { C.destroy(); M.destroy(); } } #[test] @@ -495,84 +314,41 @@ mod tests { #[test] fn wait_timeout_ms() { - static C: StaticCondvar = StaticCondvar::new(); - static M: StaticMutex = StaticMutex::new(); + 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 (g, _no_timeout) = C.wait_timeout(g, Duration::from_millis(1)).unwrap(); + 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 // assert!(!no_timeout); let _t = thread::spawn(move || { - let _g = M.lock().unwrap(); - C.notify_one(); + let _g = m2.lock().unwrap(); + c2.notify_one(); }); - let (g, timeout_res) = C.wait_timeout(g, Duration::from_millis(u32::MAX as u64)).unwrap(); + let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u32::MAX as u64)).unwrap(); assert!(!timeout_res.timed_out()); drop(g); - unsafe { C.destroy(); M.destroy(); } - } - - #[test] - fn wait_timeout_with() { - static C: StaticCondvar = StaticCondvar::new(); - static M: StaticMutex = StaticMutex::new(); - static S: AtomicUsize = AtomicUsize::new(0); - - let g = M.lock().unwrap(); - let (g, timed_out) = C.wait_timeout_with(g, Duration::new(0, 1000), |_| { - false - }).unwrap(); - assert!(timed_out.timed_out()); - - let (tx, rx) = channel(); - let _t = thread::spawn(move || { - rx.recv().unwrap(); - let g = M.lock().unwrap(); - S.store(1, Ordering::SeqCst); - C.notify_one(); - drop(g); - - rx.recv().unwrap(); - let g = M.lock().unwrap(); - S.store(2, Ordering::SeqCst); - C.notify_one(); - drop(g); - - rx.recv().unwrap(); - let _g = M.lock().unwrap(); - S.store(3, Ordering::SeqCst); - C.notify_one(); - }); - - let mut state = 0; - let day = 24 * 60 * 60; - let (_g, timed_out) = C.wait_timeout_with(g, Duration::new(day, 0), |_| { - assert_eq!(state, S.load(Ordering::SeqCst)); - tx.send(()).unwrap(); - state += 1; - match state { - 1|2 => false, - _ => true, - } - }).unwrap(); - assert!(!timed_out.timed_out()); } #[test] #[should_panic] fn two_mutexes() { - static M1: StaticMutex = StaticMutex::new(); - static M2: StaticMutex = StaticMutex::new(); - static C: StaticCondvar = StaticCondvar::new(); + let m = Arc::new(Mutex::new(())); + let m2 = m.clone(); + let c = Arc::new(Condvar::new()); + let c2 = c.clone(); - let mut g = M1.lock().unwrap(); + let mut g = m.lock().unwrap(); let _t = thread::spawn(move|| { - let _g = M1.lock().unwrap(); - C.notify_one(); + let _g = m2.lock().unwrap(); + c2.notify_one(); }); - g = C.wait(g).unwrap(); + g = c.wait(g).unwrap(); drop(g); - let _ = C.wait(M2.lock().unwrap()).unwrap(); + let m = Mutex::new(()); + let _ = c.wait(m.lock().unwrap()).unwrap(); } } diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs index 56eb7340c89..289b47b3484 100644 --- a/src/libstd/sync/mod.rs +++ b/src/libstd/sync/mod.rs @@ -25,23 +25,15 @@ pub use core::sync::atomic; #[stable(feature = "rust1", since = "1.0.0")] pub use self::barrier::{Barrier, BarrierWaitResult}; #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -pub use self::condvar::{Condvar, StaticCondvar, WaitTimeoutResult, CONDVAR_INIT}; +pub use self::condvar::{Condvar, WaitTimeoutResult}; #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -pub use self::mutex::MUTEX_INIT; -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -pub use self::mutex::{Mutex, MutexGuard, StaticMutex}; +pub use self::mutex::{Mutex, MutexGuard}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::once::{Once, OnceState, ONCE_INIT}; #[stable(feature = "rust1", since = "1.0.0")] pub use sys_common::poison::{PoisonError, TryLockError, TryLockResult, LockResult}; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::rwlock::{RwLockReadGuard, RwLockWriteGuard}; -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -pub use self::rwlock::{RwLock, StaticRwLock, RW_LOCK_INIT}; +pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; pub mod mpsc; diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index c75a5c09146..6bc458397f1 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -113,14 +113,14 @@ use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; /// *guard += 1; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] pub struct Mutex<T: ?Sized> { - // Note that this static mutex is in a *box*, not inlined into the struct - // itself. Once a native mutex has been used once, its address can never - // change (it can't be moved). This mutex type can be safely moved at any - // time, so to ensure that the native mutex is used correctly we box the - // inner lock to give it a constant address. - inner: Box<StaticMutex>, + // Note that this mutex is in a *box*, not inlined into the struct itself. + // Once a native mutex has been used once, its address can never change (it + // can't be moved). This mutex type can be safely moved at any time, so to + // ensure that the native mutex is used correctly we box the inner lock to + // give it a constant address. + inner: Box<sys::Mutex>, + poison: poison::Flag, data: UnsafeCell<T>, } @@ -131,42 +131,6 @@ unsafe impl<T: ?Sized + Send> Send for Mutex<T> { } #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<T: ?Sized + Send> Sync for Mutex<T> { } -/// The static mutex type is provided to allow for static allocation of mutexes. -/// -/// Note that this is a separate type because using a Mutex correctly means that -/// it needs to have a destructor run. In Rust, statics are not allowed to have -/// destructors. As a result, a `StaticMutex` has one extra method when compared -/// to a `Mutex`, a `destroy` method. This method is unsafe to call, and -/// documentation can be found directly on the method. -/// -/// # Examples -/// -/// ``` -/// #![feature(static_mutex)] -/// -/// use std::sync::{StaticMutex, MUTEX_INIT}; -/// -/// static LOCK: StaticMutex = MUTEX_INIT; -/// -/// { -/// let _g = LOCK.lock().unwrap(); -/// // do some productive work -/// } -/// // lock is unlocked here. -/// ``` -#[unstable(feature = "static_mutex", - reason = "may be merged with Mutex in the future", - issue = "27717")] -#[rustc_deprecated(since = "1.10.0", - reason = "the lazy-static crate suffices for static sync \ - primitives and eventually this type shouldn't \ - be necessary as `Mutex::new` in a static should \ - suffice")] -pub struct StaticMutex { - lock: sys::Mutex, - poison: poison::Flag, -} - /// An RAII implementation of a "scoped lock" of a mutex. When this structure is /// dropped (falls out of scope), the lock will be unlocked. /// @@ -174,48 +138,32 @@ pub struct StaticMutex { /// `Deref` and `DerefMut` implementations #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] pub struct MutexGuard<'a, T: ?Sized + 'a> { // funny underscores due to how Deref/DerefMut currently work (they // disregard field privacy). - __lock: &'a StaticMutex, - __data: &'a mut T, + __lock: &'a Mutex<T>, __poison: poison::Guard, } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized> !marker::Send for MutexGuard<'a, T> {} -/// Static initialization of a mutex. This constant can be used to initialize -/// other mutex constants. -#[unstable(feature = "static_mutex", - reason = "may be merged with Mutex in the future", - issue = "27717")] -#[rustc_deprecated(since = "1.10.0", - reason = "the lazy-static crate suffices for static sync \ - primitives and eventually this type shouldn't \ - be necessary as `Mutex::new` in a static should \ - suffice")] -#[allow(deprecated)] -pub const MUTEX_INIT: StaticMutex = StaticMutex::new(); - -#[allow(deprecated)] impl<T> Mutex<T> { /// Creates a new mutex in an unlocked state ready for use. #[stable(feature = "rust1", since = "1.0.0")] pub fn new(t: T) -> Mutex<T> { let mut m = Mutex { - inner: box StaticMutex::new(), + inner: box sys::Mutex::new(), + poison: poison::Flag::new(), data: UnsafeCell::new(t), }; unsafe { - m.inner.lock.init(); + m.inner.init(); } m } } -#[allow(deprecated)] impl<T: ?Sized> Mutex<T> { /// Acquires a mutex, blocking the current thread until it is able to do so. /// @@ -240,8 +188,8 @@ impl<T: ?Sized> Mutex<T> { #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> LockResult<MutexGuard<T>> { unsafe { - self.inner.lock.lock(); - MutexGuard::new(&*self.inner, &self.data) + self.inner.lock(); + MutexGuard::new(self) } } @@ -261,8 +209,8 @@ impl<T: ?Sized> Mutex<T> { #[stable(feature = "rust1", since = "1.0.0")] pub fn try_lock(&self) -> TryLockResult<MutexGuard<T>> { unsafe { - if self.inner.lock.try_lock() { - Ok(MutexGuard::new(&*self.inner, &self.data)?) + if self.inner.try_lock() { + Ok(MutexGuard::new(self)?) } else { Err(TryLockError::WouldBlock) } @@ -277,7 +225,7 @@ impl<T: ?Sized> Mutex<T> { #[inline] #[stable(feature = "sync_poison", since = "1.2.0")] pub fn is_poisoned(&self) -> bool { - self.inner.poison.get() + self.poison.get() } /// Consumes this mutex, returning the underlying data. @@ -289,21 +237,22 @@ impl<T: ?Sized> Mutex<T> { #[stable(feature = "mutex_into_inner", since = "1.6.0")] pub fn into_inner(self) -> LockResult<T> where T: Sized { // We know statically that there are no outstanding references to - // `self` so there's no need to lock the inner StaticMutex. + // `self` so there's no need to lock the inner lock. // // To get the inner value, we'd like to call `data.into_inner()`, // but because `Mutex` impl-s `Drop`, we can't move out of it, so // we'll have to destructure it manually instead. unsafe { - // Like `let Mutex { inner, data } = self`. - let (inner, data) = { - let Mutex { ref inner, ref data } = self; - (ptr::read(inner), ptr::read(data)) + // Like `let Mutex { inner, poison, data } = self`. + let (inner, poison, data) = { + let Mutex { ref inner, ref poison, ref data } = self; + (ptr::read(inner), ptr::read(poison), ptr::read(data)) }; mem::forget(self); - inner.lock.destroy(); // Keep in sync with the `Drop` impl. + inner.destroy(); // Keep in sync with the `Drop` impl. + drop(inner); - poison::map_result(inner.poison.borrow(), |_| data.into_inner()) + poison::map_result(poison.borrow(), |_| data.into_inner()) } } @@ -319,14 +268,13 @@ impl<T: ?Sized> Mutex<T> { #[stable(feature = "mutex_get_mut", since = "1.6.0")] pub fn get_mut(&mut self) -> LockResult<&mut T> { // We know statically that there are no other references to `self`, so - // there's no need to lock the inner StaticMutex. + // there's no need to lock the inner lock. let data = unsafe { &mut *self.data.get() }; - poison::map_result(self.inner.poison.borrow(), |_| data ) + poison::map_result(self.poison.borrow(), |_| data ) } } #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] impl<T: ?Sized> Drop for Mutex<T> { #[unsafe_destructor_blind_to_params] fn drop(&mut self) { @@ -335,7 +283,7 @@ impl<T: ?Sized> Drop for Mutex<T> { // dropped, that's not our job) // // IMPORTANT: This code must be kept in sync with `Mutex::into_inner`. - unsafe { self.inner.lock.destroy() } + unsafe { self.inner.destroy() } } } @@ -359,72 +307,11 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> { } } -struct Dummy(UnsafeCell<()>); -unsafe impl Sync for Dummy {} -static DUMMY: Dummy = Dummy(UnsafeCell::new(())); - -#[unstable(feature = "static_mutex", - reason = "may be merged with Mutex in the future", - issue = "27717")] -#[rustc_deprecated(since = "1.10.0", - reason = "the lazy-static crate suffices for static sync \ - primitives and eventually this type shouldn't \ - be necessary as `Mutex::new` in a static should \ - suffice")] -#[allow(deprecated)] -impl StaticMutex { - /// Creates a new mutex in an unlocked state ready for use. - pub const fn new() -> StaticMutex { - StaticMutex { - lock: sys::Mutex::new(), - poison: poison::Flag::new(), - } - } - - /// Acquires this lock, see `Mutex::lock` - #[inline] - pub fn lock(&'static self) -> LockResult<MutexGuard<()>> { - unsafe { - self.lock.lock(); - MutexGuard::new(self, &DUMMY.0) - } - } - - /// Attempts to grab this lock, see `Mutex::try_lock` - #[inline] - pub fn try_lock(&'static self) -> TryLockResult<MutexGuard<()>> { - unsafe { - if self.lock.try_lock() { - Ok(MutexGuard::new(self, &DUMMY.0)?) - } else { - Err(TryLockError::WouldBlock) - } - } - } - - /// Deallocates resources associated with this static mutex. - /// - /// This method is unsafe because it provides no guarantees that there are - /// no active users of this mutex, and safety is not guaranteed if there are - /// active users of this mutex. - /// - /// This method is required to ensure that there are no memory leaks on - /// *all* platforms. It may be the case that some platforms do not leak - /// memory if this method is not called, but this is not guaranteed to be - /// true on all platforms. - pub unsafe fn destroy(&'static self) { - self.lock.destroy() - } -} - -#[allow(deprecated)] impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { - unsafe fn new(lock: &'mutex StaticMutex, data: &'mutex UnsafeCell<T>) - -> LockResult<MutexGuard<'mutex, T>> { + unsafe fn new(lock: &'mutex Mutex<T>) -> LockResult<MutexGuard<'mutex, T>> { poison::map_result(lock.poison.borrow(), |guard| { MutexGuard { __lock: lock, - __data: &mut *data.get(), __poison: guard, } }) @@ -435,43 +322,43 @@ impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { impl<'mutex, T: ?Sized> Deref for MutexGuard<'mutex, T> { type Target = T; - fn deref(&self) -> &T {self.__data } + fn deref(&self) -> &T { + unsafe { &*self.__lock.data.get() } + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'mutex, T: ?Sized> DerefMut for MutexGuard<'mutex, T> { - fn deref_mut(&mut self) -> &mut T { self.__data } + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.__lock.data.get() } + } } #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { #[inline] fn drop(&mut self) { unsafe { self.__lock.poison.done(&self.__poison); - self.__lock.lock.unlock(); + self.__lock.inner.unlock(); } } } -#[allow(deprecated)] pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { - &guard.__lock.lock + &guard.__lock.inner } -#[allow(deprecated)] pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { &guard.__lock.poison } #[cfg(test)] -#[allow(deprecated)] mod tests { use prelude::v1::*; use sync::mpsc::channel; - use sync::{Arc, Mutex, StaticMutex, Condvar}; + use sync::{Arc, Mutex, Condvar}; use sync::atomic::{AtomicUsize, Ordering}; use thread; @@ -491,47 +378,33 @@ mod tests { } #[test] - fn smoke_static() { - static M: StaticMutex = StaticMutex::new(); - unsafe { - drop(M.lock().unwrap()); - drop(M.lock().unwrap()); - M.destroy(); - } - } - - #[test] fn lots_and_lots() { - static M: StaticMutex = StaticMutex::new(); - static mut CNT: u32 = 0; const J: u32 = 1000; const K: u32 = 3; - fn inc() { + let m = Arc::new(Mutex::new(0)); + + fn inc(m: &Mutex<u32>) { for _ in 0..J { - unsafe { - let _g = M.lock().unwrap(); - CNT += 1; - } + *m.lock().unwrap() += 1; } } let (tx, rx) = channel(); for _ in 0..K { let tx2 = tx.clone(); - thread::spawn(move|| { inc(); tx2.send(()).unwrap(); }); + let m2 = m.clone(); + thread::spawn(move|| { inc(&m2); tx2.send(()).unwrap(); }); let tx2 = tx.clone(); - thread::spawn(move|| { inc(); tx2.send(()).unwrap(); }); + let m2 = m.clone(); + thread::spawn(move|| { inc(&m2); tx2.send(()).unwrap(); }); } drop(tx); for _ in 0..2 * K { rx.recv().unwrap(); } - assert_eq!(unsafe {CNT}, J * K * 2); - unsafe { - M.destroy(); - } + assert_eq!(*m.lock().unwrap(), J * K * 2); } #[test] diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 03d3483902d..65b5686de86 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -66,9 +66,9 @@ use sys_common::rwlock as sys; /// } // write lock is dropped here /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] pub struct RwLock<T: ?Sized> { - inner: Box<StaticRwLock>, + inner: Box<sys::RWLock>, + poison: poison::Flag, data: UnsafeCell<T>, } @@ -77,64 +77,12 @@ unsafe impl<T: ?Sized + Send + Sync> Send for RwLock<T> {} #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {} -/// Structure representing a statically allocated RwLock. -/// -/// This structure is intended to be used inside of a `static` and will provide -/// automatic global access as well as lazy initialization. The internal -/// resources of this RwLock, however, must be manually deallocated. -/// -/// # Examples -/// -/// ``` -/// #![feature(static_rwlock)] -/// -/// use std::sync::{StaticRwLock, RW_LOCK_INIT}; -/// -/// static LOCK: StaticRwLock = RW_LOCK_INIT; -/// -/// { -/// let _g = LOCK.read().unwrap(); -/// // ... shared read access -/// } -/// { -/// let _g = LOCK.write().unwrap(); -/// // ... exclusive write access -/// } -/// unsafe { LOCK.destroy() } // free all resources -/// ``` -#[unstable(feature = "static_rwlock", - reason = "may be merged with RwLock in the future", - issue = "27717")] -#[rustc_deprecated(since = "1.10.0", - reason = "the lazy-static crate suffices for static sync \ - primitives and eventually this type shouldn't \ - be necessary as `RwLock::new` in a static should \ - suffice")] -pub struct StaticRwLock { - lock: sys::RWLock, - poison: poison::Flag, -} - -/// Constant initialization for a statically-initialized rwlock. -#[unstable(feature = "static_rwlock", - reason = "may be merged with RwLock in the future", - issue = "27717")] -#[rustc_deprecated(since = "1.10.0", - reason = "the lazy-static crate suffices for static sync \ - primitives and eventually this type shouldn't \ - be necessary as `RwLock::new` in a static should \ - suffice")] -#[allow(deprecated)] -pub const RW_LOCK_INIT: StaticRwLock = StaticRwLock::new(); - /// RAII structure used to release the shared read access of a lock when /// dropped. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { - __lock: &'a StaticRwLock, - __data: &'a T, + __lock: &'a RwLock<T>, } #[stable(feature = "rust1", since = "1.0.0")] @@ -144,17 +92,14 @@ impl<'a, T: ?Sized> !marker::Send for RwLockReadGuard<'a, T> {} /// dropped. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { - __lock: &'a StaticRwLock, - __data: &'a mut T, + __lock: &'a RwLock<T>, __poison: poison::Guard, } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized> !marker::Send for RwLockWriteGuard<'a, T> {} -#[allow(deprecated)] impl<T> RwLock<T> { /// Creates a new instance of an `RwLock<T>` which is unlocked. /// @@ -167,11 +112,14 @@ impl<T> RwLock<T> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(t: T) -> RwLock<T> { - RwLock { inner: box StaticRwLock::new(), data: UnsafeCell::new(t) } + RwLock { + inner: box sys::RWLock::new(), + poison: poison::Flag::new(), + data: UnsafeCell::new(t), + } } } -#[allow(deprecated)] impl<T: ?Sized> RwLock<T> { /// Locks this rwlock with shared read access, blocking the current thread /// until it can be acquired. @@ -194,8 +142,8 @@ impl<T: ?Sized> RwLock<T> { #[stable(feature = "rust1", since = "1.0.0")] pub fn read(&self) -> LockResult<RwLockReadGuard<T>> { unsafe { - self.inner.lock.read(); - RwLockReadGuard::new(&*self.inner, &self.data) + self.inner.read(); + RwLockReadGuard::new(self) } } @@ -220,8 +168,8 @@ impl<T: ?Sized> RwLock<T> { #[stable(feature = "rust1", since = "1.0.0")] pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<T>> { unsafe { - if self.inner.lock.try_read() { - Ok(RwLockReadGuard::new(&*self.inner, &self.data)?) + if self.inner.try_read() { + Ok(RwLockReadGuard::new(self)?) } else { Err(TryLockError::WouldBlock) } @@ -246,8 +194,8 @@ impl<T: ?Sized> RwLock<T> { #[stable(feature = "rust1", since = "1.0.0")] pub fn write(&self) -> LockResult<RwLockWriteGuard<T>> { unsafe { - self.inner.lock.write(); - RwLockWriteGuard::new(&*self.inner, &self.data) + self.inner.write(); + RwLockWriteGuard::new(self) } } @@ -272,8 +220,8 @@ impl<T: ?Sized> RwLock<T> { #[stable(feature = "rust1", since = "1.0.0")] pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<T>> { unsafe { - if self.inner.lock.try_write() { - Ok(RwLockWriteGuard::new(&*self.inner, &self.data)?) + if self.inner.try_write() { + Ok(RwLockWriteGuard::new(self)?) } else { Err(TryLockError::WouldBlock) } @@ -288,7 +236,7 @@ impl<T: ?Sized> RwLock<T> { #[inline] #[stable(feature = "sync_poison", since = "1.2.0")] pub fn is_poisoned(&self) -> bool { - self.inner.poison.get() + self.poison.get() } /// Consumes this `RwLock`, returning the underlying data. @@ -302,21 +250,22 @@ impl<T: ?Sized> RwLock<T> { #[stable(feature = "rwlock_into_inner", since = "1.6.0")] pub fn into_inner(self) -> LockResult<T> where T: Sized { // We know statically that there are no outstanding references to - // `self` so there's no need to lock the inner StaticRwLock. + // `self` so there's no need to lock the inner lock. // // To get the inner value, we'd like to call `data.into_inner()`, // but because `RwLock` impl-s `Drop`, we can't move out of it, so // we'll have to destructure it manually instead. unsafe { - // Like `let RwLock { inner, data } = self`. - let (inner, data) = { - let RwLock { ref inner, ref data } = self; - (ptr::read(inner), ptr::read(data)) + // Like `let RwLock { inner, poison, data } = self`. + let (inner, poison, data) = { + let RwLock { ref inner, ref poison, ref data } = self; + (ptr::read(inner), ptr::read(poison), ptr::read(data)) }; mem::forget(self); - inner.lock.destroy(); // Keep in sync with the `Drop` impl. + inner.destroy(); // Keep in sync with the `Drop` impl. + drop(inner); - poison::map_result(inner.poison.borrow(), |_| data.into_inner()) + poison::map_result(poison.borrow(), |_| data.into_inner()) } } @@ -334,19 +283,18 @@ impl<T: ?Sized> RwLock<T> { #[stable(feature = "rwlock_get_mut", since = "1.6.0")] pub fn get_mut(&mut self) -> LockResult<&mut T> { // We know statically that there are no other references to `self`, so - // there's no need to lock the inner StaticRwLock. + // there's no need to lock the inner lock. let data = unsafe { &mut *self.data.get() }; - poison::map_result(self.inner.poison.borrow(), |_| data ) + poison::map_result(self.poison.borrow(), |_| data) } } #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] impl<T: ?Sized> Drop for RwLock<T> { #[unsafe_destructor_blind_to_params] fn drop(&mut self) { // IMPORTANT: This code needs to be kept in sync with `RwLock::into_inner`. - unsafe { self.inner.lock.destroy() } + unsafe { self.inner.destroy() } } } @@ -370,114 +318,23 @@ impl<T: Default> Default for RwLock<T> { } } -struct Dummy(UnsafeCell<()>); -unsafe impl Sync for Dummy {} -static DUMMY: Dummy = Dummy(UnsafeCell::new(())); - -#[unstable(feature = "static_rwlock", - reason = "may be merged with RwLock in the future", - issue = "27717")] -#[rustc_deprecated(since = "1.10.0", - reason = "the lazy-static crate suffices for static sync \ - primitives and eventually this type shouldn't \ - be necessary as `RwLock::new` in a static should \ - suffice")] -#[allow(deprecated)] -impl StaticRwLock { - /// Creates a new rwlock. - pub const fn new() -> StaticRwLock { - StaticRwLock { - lock: sys::RWLock::new(), - poison: poison::Flag::new(), - } - } - - /// Locks this rwlock with shared read access, blocking the current thread - /// until it can be acquired. - /// - /// See `RwLock::read`. - #[inline] - pub fn read(&'static self) -> LockResult<RwLockReadGuard<'static, ()>> { - unsafe { - self.lock.read(); - RwLockReadGuard::new(self, &DUMMY.0) - } - } - - /// Attempts to acquire this lock with shared read access. - /// - /// See `RwLock::try_read`. - #[inline] - pub fn try_read(&'static self) - -> TryLockResult<RwLockReadGuard<'static, ()>> { - unsafe { - if self.lock.try_read(){ - Ok(RwLockReadGuard::new(self, &DUMMY.0)?) - } else { - Err(TryLockError::WouldBlock) - } - } - } - - /// Locks this rwlock with exclusive write access, blocking the current - /// thread until it can be acquired. - /// - /// See `RwLock::write`. - #[inline] - pub fn write(&'static self) -> LockResult<RwLockWriteGuard<'static, ()>> { - unsafe { - self.lock.write(); - RwLockWriteGuard::new(self, &DUMMY.0) - } - } - - /// Attempts to lock this rwlock with exclusive write access. - /// - /// See `RwLock::try_write`. - #[inline] - pub fn try_write(&'static self) - -> TryLockResult<RwLockWriteGuard<'static, ()>> { - unsafe { - if self.lock.try_write() { - Ok(RwLockWriteGuard::new(self, &DUMMY.0)?) - } else { - Err(TryLockError::WouldBlock) - } - } - } - - /// Deallocates all resources associated with this static lock. - /// - /// This method is unsafe to call as there is no guarantee that there are no - /// active users of the lock, and this also doesn't prevent any future users - /// of this lock. This method is required to be called to not leak memory on - /// all platforms. - pub unsafe fn destroy(&'static self) { - self.lock.destroy() - } -} - -#[allow(deprecated)] impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { - unsafe fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell<T>) - -> LockResult<RwLockReadGuard<'rwlock, T>> { + unsafe fn new(lock: &'rwlock RwLock<T>) + -> LockResult<RwLockReadGuard<'rwlock, T>> { poison::map_result(lock.poison.borrow(), |_| { RwLockReadGuard { __lock: lock, - __data: &*data.get(), } }) } } -#[allow(deprecated)] impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { - unsafe fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell<T>) - -> LockResult<RwLockWriteGuard<'rwlock, T>> { + unsafe fn new(lock: &'rwlock RwLock<T>) + -> LockResult<RwLockWriteGuard<'rwlock, T>> { poison::map_result(lock.poison.borrow(), |guard| { RwLockWriteGuard { __lock: lock, - __data: &mut *data.get(), __poison: guard, } }) @@ -488,42 +345,43 @@ impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { impl<'rwlock, T: ?Sized> Deref for RwLockReadGuard<'rwlock, T> { type Target = T; - fn deref(&self) -> &T { self.__data } + fn deref(&self) -> &T { + unsafe { &*self.__lock.data.get() } + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'rwlock, T: ?Sized> Deref for RwLockWriteGuard<'rwlock, T> { type Target = T; - fn deref(&self) -> &T { self.__data } + fn deref(&self) -> &T { + unsafe { &*self.__lock.data.get() } + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'rwlock, T: ?Sized> DerefMut for RwLockWriteGuard<'rwlock, T> { fn deref_mut(&mut self) -> &mut T { - self.__data + unsafe { &mut *self.__lock.data.get() } } } -#[allow(deprecated)] #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized> Drop for RwLockReadGuard<'a, T> { fn drop(&mut self) { - unsafe { self.__lock.lock.read_unlock(); } + unsafe { self.__lock.inner.read_unlock(); } } } -#[allow(deprecated)] #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized> Drop for RwLockWriteGuard<'a, T> { fn drop(&mut self) { self.__lock.poison.done(&self.__poison); - unsafe { self.__lock.lock.write_unlock(); } + unsafe { self.__lock.inner.write_unlock(); } } } #[cfg(test)] -#[allow(deprecated)] mod tests { #![allow(deprecated)] // rand @@ -532,7 +390,7 @@ mod tests { use rand::{self, Rng}; use sync::mpsc::channel; use thread; - use sync::{Arc, RwLock, StaticRwLock, TryLockError}; + use sync::{Arc, RwLock, TryLockError}; use sync::atomic::{AtomicUsize, Ordering}; #[derive(Eq, PartialEq, Debug)] @@ -548,31 +406,23 @@ mod tests { } #[test] - fn static_smoke() { - static R: StaticRwLock = StaticRwLock::new(); - drop(R.read().unwrap()); - drop(R.write().unwrap()); - drop((R.read().unwrap(), R.read().unwrap())); - drop(R.write().unwrap()); - unsafe { R.destroy(); } - } - - #[test] fn frob() { - static R: StaticRwLock = StaticRwLock::new(); const N: usize = 10; const M: usize = 1000; + let r = Arc::new(RwLock::new(())); + let (tx, rx) = channel::<()>(); for _ in 0..N { let tx = tx.clone(); - thread::spawn(move|| { + let r = r.clone(); + thread::spawn(move || { let mut rng = rand::thread_rng(); for _ in 0..M { if rng.gen_weighted_bool(N) { - drop(R.write().unwrap()); + drop(r.write().unwrap()); } else { - drop(R.read().unwrap()); + drop(r.read().unwrap()); } } drop(tx); @@ -580,7 +430,6 @@ mod tests { } drop(tx); let _ = rx.recv(); - unsafe { R.destroy(); } } #[test] |
