提交 a7220d90 编写于 作者: A Alex Crichton

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<bool>` was changed to an `AtomicBool` to prevent
the associated data race. Otherwise the usage/gurantees should be the same
they were before.
上级 31e9ed5d
......@@ -1244,39 +1244,6 @@ pub fn peek(&mut self) -> Option<&I::Item> {
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.
......
......@@ -15,7 +15,7 @@
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 @@ pub fn timed_out(&self) -> bool {
/// }
/// ```
#[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 @@ pub fn new() -> 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 @@ pub fn wait_timeout_ms<'a, T>(&self, guard: MutexGuard<'a, T>, ms: u32)
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 @@ pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>,
///
/// 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 @@ pub fn notify_one(&self) { unsafe { self.inner.inner.notify_one() } }
///
/// 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 @@ fn verify(&self, mutex: &sys_mutex::Mutex) {
}
}
#[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 @@ fn smoke() {
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 @@ fn notify_all() {
#[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();
}
}
......@@ -25,23 +25,15 @@
#[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;
......
......@@ -113,14 +113,14 @@
/// *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 @@ pub fn lock(&self) -> LockResult<MutexGuard<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 @@ pub fn try_lock(&self) -> TryLockResult<MutexGuard<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 @@ pub fn is_poisoned(&self) -> bool {
#[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 @@ pub fn into_inner(self) -> LockResult<T> where T: Sized {
#[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 @@ fn drop(&mut self) {
// 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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
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 @@ unsafe fn new(lock: &'mutex StaticMutex, data: &'mutex UnsafeCell<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 @@ fn smoke() {
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<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]
......
......@@ -66,9 +66,9 @@
/// } // 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 @@ pub fn read(&self) -> LockResult<RwLockReadGuard<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 @@ pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<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 @@ pub fn write(&self) -> LockResult<RwLockWriteGuard<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 @@ pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<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 @@ pub fn is_poisoned(&self) -> bool {
#[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 @@ pub fn into_inner(self) -> LockResult<T> where T: Sized {
#[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 @@ fn default() -> 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 @@ unsafe fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell<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 @@ fn smoke() {
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 @@ fn frob() {
}
drop(tx);
let _ = rx.recv();
unsafe { R.destroy(); }
}
#[test]
......
......@@ -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<bool> }
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 @@ pub fn borrow(&self) -> LockResult<Guard> {
#[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)
}
}
......
......@@ -30,9 +30,9 @@
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 @@ fn drop(&mut self) {
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(())
}
......@@ -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;
}
......@@ -18,9 +18,6 @@
fn assert_both<T: Sync + Send>() {}
fn main() {
assert_both::<sync::StaticMutex>();
assert_both::<sync::StaticCondvar>();
assert_both::<sync::StaticRwLock>();
assert_both::<sync::Mutex<()>>();
assert_both::<sync::Condvar>();
assert_both::<sync::RwLock<()>>();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册