From a7220d9046e292869dded2c478544850c220c7de Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 7 Jul 2016 11:46:09 -0700 Subject: [PATCH] std: Clean out deprecated APIs This primarily removes a lot of `sync::Static*` APIs and rejiggers the associated implementations. While doing this it was discovered that the `is_poisoned` method can actually result in a data race for the Mutex/RwLock primitives, so the inner `Cell` was changed to an `AtomicBool` to prevent the associated data race. Otherwise the usage/gurantees should be the same they were before. --- src/libcore/iter/mod.rs | 33 -- src/libstd/sync/condvar.rs | 368 ++++-------------- src/libstd/sync/mod.rs | 14 +- src/libstd/sync/mutex.rs | 219 +++-------- src/libstd/sync/rwlock.rs | 249 +++--------- src/libstd/sys/common/poison.rs | 24 +- src/libstd/sys/windows/backtrace.rs | 92 +++-- src/test/debuginfo/constant-debug-locs.rs | 2 - .../run-pass/std-sync-right-kind-impls.rs | 3 - 9 files changed, 234 insertions(+), 770 deletions(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index dffe9dee022a6..d2de0d46d746b 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -1244,39 +1244,6 @@ impl Peekable { None => None, } } - - /// Checks if the iterator has finished iterating. - /// - /// Returns `true` if there are no more elements in the iterator, and - /// `false` if there are. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(peekable_is_empty)] - /// - /// let xs = [1, 2, 3]; - /// - /// let mut iter = xs.iter().peekable(); - /// - /// // There are still elements to iterate over - /// assert_eq!(iter.is_empty(), false); - /// - /// // Let's consume the iterator - /// iter.next(); - /// iter.next(); - /// iter.next(); - /// - /// assert_eq!(iter.is_empty(), true); - /// ``` - #[unstable(feature = "peekable_is_empty", issue = "32111")] - #[inline] - #[rustc_deprecated(since = "1.10.0", reason = "replaced by .peek().is_none()")] - pub fn is_empty(&mut self) -> bool { - self.peek().is_none() - } } /// An iterator that rejects elements while `predicate` is true. diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index bf4b119a0b666..3c52ebc72f2cb 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 } - -/// 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, 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> { - 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> { - 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> = 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; @@ -434,27 +260,20 @@ mod tests { c.notify_all(); } - #[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 56eb7340c890c..289b47b34847f 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 c75a5c09146a4..6bc458397f163 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 { - // 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, + // 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, + poison: poison::Flag, data: UnsafeCell, } @@ -131,42 +131,6 @@ unsafe impl Send for Mutex { } #[stable(feature = "rust1", since = "1.0.0")] unsafe impl Sync for Mutex { } -/// 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, __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 Mutex { /// Creates a new mutex in an unlocked state ready for use. #[stable(feature = "rust1", since = "1.0.0")] pub fn new(t: T) -> Mutex { 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 Mutex { /// Acquires a mutex, blocking the current thread until it is able to do so. /// @@ -240,8 +188,8 @@ impl Mutex { #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> LockResult> { unsafe { - self.inner.lock.lock(); - MutexGuard::new(&*self.inner, &self.data) + self.inner.lock(); + MutexGuard::new(self) } } @@ -261,8 +209,8 @@ impl Mutex { #[stable(feature = "rust1", since = "1.0.0")] pub fn try_lock(&self) -> TryLockResult> { 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 Mutex { #[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 Mutex { #[stable(feature = "mutex_into_inner", since = "1.6.0")] pub fn into_inner(self) -> LockResult 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 Mutex { #[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 Drop for Mutex { #[unsafe_destructor_blind_to_params] fn drop(&mut self) { @@ -335,7 +283,7 @@ impl Drop for Mutex { // 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 fmt::Debug for Mutex { } } -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> { - 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> { - 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) - -> LockResult> { + unsafe fn new(lock: &'mutex Mutex) -> LockResult> { 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; @@ -490,48 +377,34 @@ mod tests { drop(m.lock().unwrap()); } - #[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) { 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 03d3483902dcf..65b5686de869c 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 { - inner: Box, + inner: Box, + poison: poison::Flag, data: UnsafeCell, } @@ -77,64 +77,12 @@ unsafe impl Send for RwLock {} #[stable(feature = "rust1", since = "1.0.0")] unsafe impl Sync for RwLock {} -/// 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, } #[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, __poison: poison::Guard, } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized> !marker::Send for RwLockWriteGuard<'a, T> {} -#[allow(deprecated)] impl RwLock { /// Creates a new instance of an `RwLock` which is unlocked. /// @@ -167,11 +112,14 @@ impl RwLock { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(t: T) -> RwLock { - 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 RwLock { /// Locks this rwlock with shared read access, blocking the current thread /// until it can be acquired. @@ -194,8 +142,8 @@ impl RwLock { #[stable(feature = "rust1", since = "1.0.0")] pub fn read(&self) -> LockResult> { unsafe { - self.inner.lock.read(); - RwLockReadGuard::new(&*self.inner, &self.data) + self.inner.read(); + RwLockReadGuard::new(self) } } @@ -220,8 +168,8 @@ impl RwLock { #[stable(feature = "rust1", since = "1.0.0")] pub fn try_read(&self) -> TryLockResult> { 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 RwLock { #[stable(feature = "rust1", since = "1.0.0")] pub fn write(&self) -> LockResult> { unsafe { - self.inner.lock.write(); - RwLockWriteGuard::new(&*self.inner, &self.data) + self.inner.write(); + RwLockWriteGuard::new(self) } } @@ -272,8 +220,8 @@ impl RwLock { #[stable(feature = "rust1", since = "1.0.0")] pub fn try_write(&self) -> TryLockResult> { 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 RwLock { #[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 RwLock { #[stable(feature = "rwlock_into_inner", since = "1.6.0")] pub fn into_inner(self) -> LockResult 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 RwLock { #[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 Drop for RwLock { #[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 Default for RwLock { } } -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> { - 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> { - 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> { - 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> { - 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) - -> LockResult> { + unsafe fn new(lock: &'rwlock RwLock) + -> LockResult> { 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) - -> LockResult> { + unsafe fn new(lock: &'rwlock RwLock) + -> LockResult> { 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)] @@ -547,32 +405,24 @@ mod tests { drop(l.write().unwrap()); } - #[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] diff --git a/src/libstd/sys/common/poison.rs b/src/libstd/sys/common/poison.rs index 83780a31cceb1..55212bf35d698 100644 --- a/src/libstd/sys/common/poison.rs +++ b/src/libstd/sys/common/poison.rs @@ -8,22 +8,28 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use cell::Cell; use error::{Error}; use fmt; use marker::Reflect; +use sync::atomic::{AtomicBool, Ordering}; use thread; -pub struct Flag { failed: Cell } +pub struct Flag { failed: AtomicBool } -// This flag is only ever accessed with a lock previously held. Note that this -// a totally private structure. -unsafe impl Send for Flag {} -unsafe impl Sync for Flag {} +// Note that the Ordering uses to access the `failed` field of `Flag` below is +// always `Relaxed`, and that's because this isn't actually protecting any data, +// it's just a flag whether we've panicked or not. +// +// The actual location that this matters is when a mutex is **locked** which is +// where we have external synchronization ensuring that we see memory +// reads/writes to this flag. +// +// As a result, if it matters, we should see the correct value for `failed` in +// all cases. impl Flag { pub const fn new() -> Flag { - Flag { failed: Cell::new(false) } + Flag { failed: AtomicBool::new(false) } } #[inline] @@ -39,13 +45,13 @@ impl Flag { #[inline] pub fn done(&self, guard: &Guard) { if !guard.panicking && thread::panicking() { - self.failed.set(true); + self.failed.store(true, Ordering::Relaxed); } } #[inline] pub fn get(&self) -> bool { - self.failed.get() + self.failed.load(Ordering::Relaxed) } } diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs index 0e10a8d8e8dd2..82a44c1c1103b 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -30,9 +30,9 @@ use io; use libc::c_void; use mem; use ptr; -use sync::StaticMutex; use sys::c; use sys::dynamic_lib::DynamicLibrary; +use sys::mutex::Mutex; macro_rules! sym { ($lib:expr, $e:expr, $t:ident) => ( @@ -101,53 +101,59 @@ impl Drop for Cleanup { pub fn write(w: &mut Write) -> io::Result<()> { // According to windows documentation, all dbghelp functions are // single-threaded. - static LOCK: StaticMutex = StaticMutex::new(); - let _g = LOCK.lock(); + static LOCK: Mutex = Mutex::new(); + unsafe { + LOCK.lock(); + let res = _write(w); + LOCK.unlock(); + return res + } +} +unsafe fn _write(w: &mut Write) -> io::Result<()> { let dbghelp = match DynamicLibrary::open("dbghelp.dll") { Ok(lib) => lib, Err(..) => return Ok(()), }; - unsafe { - // Fetch the symbols necessary from dbghelp.dll - let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn); - let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn); - let StackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn); - - // Allocate necessary structures for doing the stack walk - let process = c::GetCurrentProcess(); - let thread = c::GetCurrentThread(); - let mut context: c::CONTEXT = mem::zeroed(); - c::RtlCaptureContext(&mut context); - let mut frame: c::STACKFRAME64 = mem::zeroed(); - let image = init_frame(&mut frame, &context); - - // Initialize this process's symbols - let ret = SymInitialize(process, ptr::null_mut(), c::TRUE); - if ret != c::TRUE { return Ok(()) } - let _c = Cleanup { handle: process, SymCleanup: SymCleanup }; - - // And now that we're done with all the setup, do the stack walking! - // Start from -1 to avoid printing this stack frame, which will - // always be exactly the same. - let mut i = -1; - write!(w, "stack backtrace:\n")?; - while StackWalk64(image, process, thread, &mut frame, &mut context, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut()) == c::TRUE { - let addr = frame.AddrPC.Offset; - if addr == frame.AddrReturn.Offset || addr == 0 || - frame.AddrReturn.Offset == 0 { break } - - i += 1; - - if i >= 0 { - printing::print(w, i, addr - 1, process, &dbghelp)?; - } - } - Ok(()) + // Fetch the symbols necessary from dbghelp.dll + let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn); + let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn); + let StackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn); + + // Allocate necessary structures for doing the stack walk + let process = c::GetCurrentProcess(); + let thread = c::GetCurrentThread(); + let mut context: c::CONTEXT = mem::zeroed(); + c::RtlCaptureContext(&mut context); + let mut frame: c::STACKFRAME64 = mem::zeroed(); + let image = init_frame(&mut frame, &context); + + // Initialize this process's symbols + let ret = SymInitialize(process, ptr::null_mut(), c::TRUE); + if ret != c::TRUE { return Ok(()) } + let _c = Cleanup { handle: process, SymCleanup: SymCleanup }; + + // And now that we're done with all the setup, do the stack walking! + // Start from -1 to avoid printing this stack frame, which will + // always be exactly the same. + let mut i = -1; + write!(w, "stack backtrace:\n")?; + while StackWalk64(image, process, thread, &mut frame, &mut context, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut()) == c::TRUE { + let addr = frame.AddrPC.Offset; + if addr == frame.AddrReturn.Offset || addr == 0 || + frame.AddrReturn.Offset == 0 { break } + + i += 1; + + if i >= 0 { + printing::print(w, i, addr - 1, process, &dbghelp)?; + } } + + Ok(()) } diff --git a/src/test/debuginfo/constant-debug-locs.rs b/src/test/debuginfo/constant-debug-locs.rs index 04e19b30fd414..7b7bda302250f 100644 --- a/src/test/debuginfo/constant-debug-locs.rs +++ b/src/test/debuginfo/constant-debug-locs.rs @@ -21,7 +21,6 @@ // This test makes sure that the compiler doesn't crash when trying to assign // debug locations to const-expressions. -use std::sync::StaticMutex; use std::cell::UnsafeCell; const CONSTANT: u64 = 3 + 4; @@ -63,6 +62,5 @@ fn main() { let mut _string = STRING; let mut _vec = VEC; let mut _nested = NESTED; - let mut _extern = StaticMutex::new(); let mut _unsafe_cell = UNSAFE_CELL; } diff --git a/src/test/run-pass/std-sync-right-kind-impls.rs b/src/test/run-pass/std-sync-right-kind-impls.rs index 7332f098b96fa..03884e8205bd2 100644 --- a/src/test/run-pass/std-sync-right-kind-impls.rs +++ b/src/test/run-pass/std-sync-right-kind-impls.rs @@ -18,9 +18,6 @@ use std::sync; fn assert_both() {} fn main() { - assert_both::(); - assert_both::(); - assert_both::(); assert_both::>(); assert_both::(); assert_both::>();