std: Stabilization pass for mutex/rwlock/condvar
This commit performs a stabilization pass over the sync::{mutex, rwlock, condvar} modules, marking the following items as stable: * Mutex * Mutex::new * Mutex::lock * Mutex::try_lock * MutexGuard * RWLock * RWLock::new * RWLock::read * RWLock::try_read * RWLock::write * RWLock::try_write * RWLockReadGuard * RWLockWriteGuard * Condvar * Condvar::new * Condvar::wait * Condvar::notify_one * Condvar::notify_all * PoisonError * TryLockError * TryLockError::Poisoned * TryLockError::WouldBlock * LockResult * TryLockResult The following items remain unstable to explore future possibilities of unifying the static/non-static variants of the types: * StaticMutex * StaticMutex::new * StaticMutex::lock * StaticMutex::try_lock * StaticMutex::desroy * StaticRWLock * StaticRWLock::new * StaticRWLock::read * StaticRWLock::try_read * StaticRWLock::write * StaticRWLock::try_write * StaticRWLock::destroy The following items were removed in favor of `Guard<'static, ()>` instead. * StaticMutexGuard * StaticRWLockReadGuard * StaticRWLockWriteGuard
This commit is contained in:
parent
76e5ed655c
commit
35e63e3827
|
@ -12,10 +12,10 @@ use prelude::*;
|
|||
|
||||
use sync::atomic::{mod, AtomicUint};
|
||||
use sync::poison::{mod, LockResult};
|
||||
use sync::CondvarGuard;
|
||||
use sys_common::condvar as sys;
|
||||
use sys_common::mutex as sys_mutex;
|
||||
use time::Duration;
|
||||
use sync::{mutex, MutexGuard};
|
||||
|
||||
/// A Condition Variable
|
||||
///
|
||||
|
@ -57,6 +57,7 @@ use time::Duration;
|
|||
/// started = cvar.wait(started).unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
#[stable]
|
||||
pub struct Condvar { inner: Box<StaticCondvar> }
|
||||
|
||||
unsafe impl Send for Condvar {}
|
||||
|
@ -74,6 +75,7 @@ unsafe impl Sync for Condvar {}
|
|||
///
|
||||
/// static CVAR: StaticCondvar = CONDVAR_INIT;
|
||||
/// ```
|
||||
#[unstable = "may be merged with Condvar in the future"]
|
||||
pub struct StaticCondvar {
|
||||
inner: sys::Condvar,
|
||||
mutex: AtomicUint,
|
||||
|
@ -83,24 +85,16 @@ unsafe impl Send for StaticCondvar {}
|
|||
unsafe impl Sync for StaticCondvar {}
|
||||
|
||||
/// Constant initializer for a statically allocated condition variable.
|
||||
#[unstable = "may be merged with Condvar in the future"]
|
||||
pub const CONDVAR_INIT: StaticCondvar = StaticCondvar {
|
||||
inner: sys::CONDVAR_INIT,
|
||||
mutex: atomic::INIT_ATOMIC_UINT,
|
||||
};
|
||||
|
||||
/// A trait for vaules which can be passed to the waiting methods of condition
|
||||
/// variables. This is implemented by the mutex guards in this module.
|
||||
///
|
||||
/// Note that this trait should likely not be implemented manually unless you
|
||||
/// really know what you're doing.
|
||||
pub trait AsGuard {
|
||||
#[allow(missing_docs)]
|
||||
fn as_guard(&self) -> CondvarGuard;
|
||||
}
|
||||
|
||||
impl Condvar {
|
||||
/// Creates a new condition variable which is ready to be waited on and
|
||||
/// notified.
|
||||
#[stable]
|
||||
pub fn new() -> Condvar {
|
||||
Condvar {
|
||||
inner: box StaticCondvar {
|
||||
|
@ -136,11 +130,12 @@ impl Condvar {
|
|||
/// over time. Each condition variable is dynamically bound to exactly one
|
||||
/// mutex to ensure defined behavior across platforms. If this functionality
|
||||
/// is not desired, then unsafe primitives in `sys` are provided.
|
||||
pub fn wait<T: AsGuard>(&self, mutex_guard: T)
|
||||
-> LockResult<T> {
|
||||
#[stable]
|
||||
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(mutex_guard)
|
||||
me.inner.wait(guard)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,11 +159,11 @@ impl Condvar {
|
|||
// provide. There are also additional concerns about the unix-specific
|
||||
// implementation which may need to be addressed.
|
||||
#[allow(dead_code)]
|
||||
fn wait_timeout<T: AsGuard>(&self, mutex_guard: T, dur: Duration)
|
||||
-> LockResult<(T, bool)> {
|
||||
fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>, dur: Duration)
|
||||
-> LockResult<(MutexGuard<'a, T>, bool)> {
|
||||
unsafe {
|
||||
let me: &'static Condvar = &*(self as *const _);
|
||||
me.inner.wait_timeout(mutex_guard, dur)
|
||||
me.inner.wait_timeout(guard, dur)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,6 +174,7 @@ impl Condvar {
|
|||
/// `notify_one` are not buffered in any way.
|
||||
///
|
||||
/// To wake up all threads, see `notify_one()`.
|
||||
#[stable]
|
||||
pub fn notify_one(&self) { unsafe { self.inner.inner.notify_one() } }
|
||||
|
||||
/// Wake up all blocked threads on this condvar.
|
||||
|
@ -188,6 +184,7 @@ impl Condvar {
|
|||
/// way.
|
||||
///
|
||||
/// To wake up only one thread, see `notify_one()`.
|
||||
#[stable]
|
||||
pub fn notify_all(&self) { unsafe { self.inner.inner.notify_all() } }
|
||||
}
|
||||
|
||||
|
@ -202,17 +199,19 @@ impl StaticCondvar {
|
|||
/// notification.
|
||||
///
|
||||
/// See `Condvar::wait`.
|
||||
pub fn wait<T: AsGuard>(&'static self, mutex_guard: T) -> LockResult<T> {
|
||||
#[unstable = "may be merged with Condvar in the future"]
|
||||
pub fn wait<'a, T>(&'static self, guard: MutexGuard<'a, T>)
|
||||
-> LockResult<MutexGuard<'a, T>> {
|
||||
let poisoned = unsafe {
|
||||
let cvar_guard = mutex_guard.as_guard();
|
||||
self.verify(cvar_guard.lock);
|
||||
self.inner.wait(cvar_guard.lock);
|
||||
cvar_guard.poisoned.get()
|
||||
let lock = mutex::guard_lock(&guard);
|
||||
self.verify(lock);
|
||||
self.inner.wait(lock);
|
||||
mutex::guard_poison(&guard).get()
|
||||
};
|
||||
if poisoned {
|
||||
Err(poison::new_poison_error(mutex_guard))
|
||||
Err(poison::new_poison_error(guard))
|
||||
} else {
|
||||
Ok(mutex_guard)
|
||||
Ok(guard)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -221,29 +220,31 @@ impl StaticCondvar {
|
|||
///
|
||||
/// See `Condvar::wait_timeout`.
|
||||
#[allow(dead_code)] // may want to stabilize this later, see wait_timeout above
|
||||
fn wait_timeout<T: AsGuard>(&'static self, mutex_guard: T, dur: Duration)
|
||||
-> LockResult<(T, bool)> {
|
||||
fn wait_timeout<'a, T>(&'static self, guard: MutexGuard<'a, T>, dur: Duration)
|
||||
-> LockResult<(MutexGuard<'a, T>, bool)> {
|
||||
let (poisoned, success) = unsafe {
|
||||
let cvar_guard = mutex_guard.as_guard();
|
||||
self.verify(cvar_guard.lock);
|
||||
let success = self.inner.wait_timeout(cvar_guard.lock, dur);
|
||||
(cvar_guard.poisoned.get(), success)
|
||||
let lock = mutex::guard_lock(&guard);
|
||||
self.verify(lock);
|
||||
let success = self.inner.wait_timeout(lock, dur);
|
||||
(mutex::guard_poison(&guard).get(), success)
|
||||
};
|
||||
if poisoned {
|
||||
Err(poison::new_poison_error((mutex_guard, success)))
|
||||
Err(poison::new_poison_error((guard, success)))
|
||||
} else {
|
||||
Ok((mutex_guard, success))
|
||||
Ok((guard, success))
|
||||
}
|
||||
}
|
||||
|
||||
/// Wake up one blocked thread on this condvar.
|
||||
///
|
||||
/// See `Condvar::notify_one`.
|
||||
#[unstable = "may be merged with Condvar in the future"]
|
||||
pub fn notify_one(&'static self) { unsafe { self.inner.notify_one() } }
|
||||
|
||||
/// Wake up all blocked threads on this condvar.
|
||||
///
|
||||
/// See `Condvar::notify_all`.
|
||||
#[unstable = "may be merged with Condvar in the future"]
|
||||
pub fn notify_all(&'static self) { unsafe { self.inner.notify_all() } }
|
||||
|
||||
/// Deallocate all resources associated with this static condvar.
|
||||
|
@ -252,6 +253,7 @@ impl StaticCondvar {
|
|||
/// 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 = "may be merged with Condvar in the future"]
|
||||
pub unsafe fn destroy(&'static self) {
|
||||
self.inner.destroy()
|
||||
}
|
||||
|
|
|
@ -17,16 +17,13 @@
|
|||
|
||||
#![experimental]
|
||||
|
||||
use sys_common::mutex as sys_mutex;
|
||||
|
||||
pub use alloc::arc::{Arc, Weak};
|
||||
|
||||
pub use self::mutex::{Mutex, MutexGuard, StaticMutex, StaticMutexGuard};
|
||||
pub use self::mutex::{Mutex, MutexGuard, StaticMutex};
|
||||
pub use self::mutex::MUTEX_INIT;
|
||||
pub use self::rwlock::{RWLock, StaticRWLock, RWLOCK_INIT};
|
||||
pub use self::rwlock::{RWLockReadGuard, RWLockWriteGuard};
|
||||
pub use self::rwlock::{StaticRWLockReadGuard, StaticRWLockWriteGuard};
|
||||
pub use self::condvar::{Condvar, StaticCondvar, CONDVAR_INIT, AsGuard};
|
||||
pub use self::condvar::{Condvar, StaticCondvar, CONDVAR_INIT};
|
||||
pub use self::once::{Once, ONCE_INIT};
|
||||
pub use self::semaphore::{Semaphore, SemaphoreGuard};
|
||||
pub use self::barrier::Barrier;
|
||||
|
@ -45,10 +42,3 @@ mod poison;
|
|||
mod rwlock;
|
||||
mod semaphore;
|
||||
mod task_pool;
|
||||
|
||||
/// Structure returned by `AsGuard` to wait on a condition variable.
|
||||
// NB: defined here to all modules have access to these private fields.
|
||||
pub struct CondvarGuard<'a> {
|
||||
lock: &'a sys_mutex::Mutex,
|
||||
poisoned: &'a poison::Flag,
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ use prelude::*;
|
|||
|
||||
use cell::UnsafeCell;
|
||||
use kinds::marker;
|
||||
use sync::{AsGuard, CondvarGuard};
|
||||
use sync::poison::{mod, TryLockError, TryLockResult, LockResult};
|
||||
use sys_common::mutex as sys;
|
||||
|
||||
|
@ -107,6 +106,7 @@ use sys_common::mutex as sys;
|
|||
///
|
||||
/// *guard += 1;
|
||||
/// ```
|
||||
#[stable]
|
||||
pub struct Mutex<T> {
|
||||
// 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
|
||||
|
@ -142,6 +142,7 @@ unsafe impl<T:Send> Sync for Mutex<T> { }
|
|||
/// }
|
||||
/// // lock is unlocked here.
|
||||
/// ```
|
||||
#[unstable = "may be merged with Mutex in the future"]
|
||||
pub struct StaticMutex {
|
||||
lock: sys::Mutex,
|
||||
poison: poison::Flag,
|
||||
|
@ -155,27 +156,19 @@ unsafe impl Sync for StaticMutex {}
|
|||
/// The data protected by the mutex can be access through this guard via its
|
||||
/// Deref and DerefMut implementations
|
||||
#[must_use]
|
||||
#[stable]
|
||||
pub struct MutexGuard<'a, T: 'a> {
|
||||
// funny underscores due to how Deref/DerefMut currently work (they
|
||||
// disregard field privacy).
|
||||
__inner: Guard<'a, Mutex<T>>,
|
||||
}
|
||||
|
||||
/// An RAII implementation of a "scoped lock" of a static mutex. When this
|
||||
/// structure is dropped (falls out of scope), the lock will be unlocked.
|
||||
#[must_use]
|
||||
pub struct StaticMutexGuard {
|
||||
inner: Guard<'static, StaticMutex>,
|
||||
}
|
||||
|
||||
struct Guard<'a, T: 'a> {
|
||||
inner: &'a T,
|
||||
poison: poison::Guard,
|
||||
marker: marker::NoSend, // even if 'a is static, this cannot be sent
|
||||
__lock: &'a StaticMutex,
|
||||
__data: &'a UnsafeCell<T>,
|
||||
__poison: poison::Guard,
|
||||
__marker: marker::NoSend,
|
||||
}
|
||||
|
||||
/// Static initialization of a mutex. This constant can be used to initialize
|
||||
/// other mutex constants.
|
||||
#[unstable = "may be merged with Mutex in the future"]
|
||||
pub const MUTEX_INIT: StaticMutex = StaticMutex {
|
||||
lock: sys::MUTEX_INIT,
|
||||
poison: poison::FLAG_INIT,
|
||||
|
@ -183,6 +176,7 @@ pub const MUTEX_INIT: StaticMutex = StaticMutex {
|
|||
|
||||
impl<T: Send> Mutex<T> {
|
||||
/// Creates a new mutex in an unlocked state ready for use.
|
||||
#[stable]
|
||||
pub fn new(t: T) -> Mutex<T> {
|
||||
Mutex {
|
||||
inner: box MUTEX_INIT,
|
||||
|
@ -201,9 +195,10 @@ impl<T: Send> Mutex<T> {
|
|||
///
|
||||
/// If another user of this mutex panicked while holding the mutex, then
|
||||
/// this call will return an error once the mutex is acquired.
|
||||
#[stable]
|
||||
pub fn lock(&self) -> LockResult<MutexGuard<T>> {
|
||||
unsafe { self.inner.lock.lock() }
|
||||
MutexGuard::new(self)
|
||||
MutexGuard::new(&*self.inner, &self.data)
|
||||
}
|
||||
|
||||
/// Attempts to acquire this lock.
|
||||
|
@ -219,9 +214,10 @@ impl<T: Send> Mutex<T> {
|
|||
/// If another user of this mutex panicked while holding the mutex, then
|
||||
/// this call will return failure if the mutex would otherwise be
|
||||
/// acquired.
|
||||
#[stable]
|
||||
pub fn try_lock(&self) -> TryLockResult<MutexGuard<T>> {
|
||||
if unsafe { self.inner.lock.try_lock() } {
|
||||
Ok(try!(MutexGuard::new(self)))
|
||||
Ok(try!(MutexGuard::new(&*self.inner, &self.data)))
|
||||
} else {
|
||||
Err(TryLockError::WouldBlock)
|
||||
}
|
||||
|
@ -238,19 +234,23 @@ impl<T: Send> Drop for Mutex<T> {
|
|||
}
|
||||
}
|
||||
|
||||
static DUMMY: UnsafeCell<()> = UnsafeCell { value: () };
|
||||
|
||||
impl StaticMutex {
|
||||
/// Acquires this lock, see `Mutex::lock`
|
||||
#[inline]
|
||||
pub fn lock(&'static self) -> LockResult<StaticMutexGuard> {
|
||||
#[unstable = "may be merged with Mutex in the future"]
|
||||
pub fn lock(&'static self) -> LockResult<MutexGuard<()>> {
|
||||
unsafe { self.lock.lock() }
|
||||
StaticMutexGuard::new(self)
|
||||
MutexGuard::new(self, &DUMMY)
|
||||
}
|
||||
|
||||
/// Attempts to grab this lock, see `Mutex::try_lock`
|
||||
#[inline]
|
||||
pub fn try_lock(&'static self) -> TryLockResult<StaticMutexGuard> {
|
||||
#[unstable = "may be merged with Mutex in the future"]
|
||||
pub fn try_lock(&'static self) -> TryLockResult<MutexGuard<()>> {
|
||||
if unsafe { self.lock.try_lock() } {
|
||||
Ok(try!(StaticMutexGuard::new(self)))
|
||||
Ok(try!(MutexGuard::new(self, &DUMMY)))
|
||||
} else {
|
||||
Err(TryLockError::WouldBlock)
|
||||
}
|
||||
|
@ -266,95 +266,56 @@ impl StaticMutex {
|
|||
/// *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.
|
||||
#[unstable = "may be merged with Mutex in the future"]
|
||||
pub unsafe fn destroy(&'static self) {
|
||||
self.lock.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'mutex, T> MutexGuard<'mutex, T> {
|
||||
fn new(lock: &Mutex<T>) -> LockResult<MutexGuard<T>> {
|
||||
poison::map_result(Guard::new(lock), |guard| {
|
||||
MutexGuard { __inner: guard }
|
||||
fn new(lock: &'mutex StaticMutex, data: &'mutex UnsafeCell<T>)
|
||||
-> LockResult<MutexGuard<'mutex, T>> {
|
||||
poison::map_result(lock.poison.borrow(), |guard| {
|
||||
MutexGuard {
|
||||
__lock: lock,
|
||||
__data: data,
|
||||
__poison: guard,
|
||||
__marker: marker::NoSend,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsGuard for Mutex<T> {
|
||||
fn as_guard(&self) -> CondvarGuard { self.inner.as_guard() }
|
||||
}
|
||||
|
||||
impl<'mutex, T> AsGuard for MutexGuard<'mutex, T> {
|
||||
fn as_guard(&self) -> CondvarGuard {
|
||||
CondvarGuard {
|
||||
lock: &self.__inner.inner.inner.lock,
|
||||
poisoned: &self.__inner.inner.inner.poison,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'mutex, T> Deref<T> for MutexGuard<'mutex, T> {
|
||||
fn deref<'a>(&'a self) -> &'a T {
|
||||
unsafe { &*self.__inner.inner.data.get() }
|
||||
unsafe { &*self.__data.get() }
|
||||
}
|
||||
}
|
||||
impl<'mutex, T> DerefMut<T> for MutexGuard<'mutex, T> {
|
||||
fn deref_mut<'a>(&'a mut self) -> &'a mut T {
|
||||
unsafe { &mut *self.__inner.inner.data.get() }
|
||||
}
|
||||
}
|
||||
|
||||
impl StaticMutexGuard {
|
||||
#[inline]
|
||||
fn new(lock: &'static StaticMutex) -> LockResult<StaticMutexGuard> {
|
||||
poison::map_result(Guard::new(lock), |guard| {
|
||||
StaticMutexGuard { inner: guard }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl AsGuard for StaticMutex {
|
||||
#[inline]
|
||||
fn as_guard(&self) -> CondvarGuard {
|
||||
CondvarGuard { lock: &self.lock, poisoned: &self.poison }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsGuard for StaticMutexGuard {
|
||||
#[inline]
|
||||
fn as_guard(&self) -> CondvarGuard {
|
||||
CondvarGuard {
|
||||
lock: &self.inner.inner.lock,
|
||||
poisoned: &self.inner.inner.poison,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: AsGuard> Guard<'a, T> {
|
||||
#[inline]
|
||||
fn new(t: &T) -> LockResult<Guard<T>> {
|
||||
let data = t.as_guard();
|
||||
poison::map_result(data.poisoned.borrow(), |guard| {
|
||||
Guard {
|
||||
inner: t,
|
||||
poison: guard,
|
||||
marker: marker::NoSend,
|
||||
}
|
||||
})
|
||||
unsafe { &mut *self.__data.get() }
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl<'a, T: AsGuard> Drop for Guard<'a, T> {
|
||||
impl<'a, T> Drop for MutexGuard<'a, T> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let data = self.inner.as_guard();
|
||||
data.poisoned.done(&self.poison);
|
||||
data.lock.unlock();
|
||||
self.__lock.poison.done(&self.__poison);
|
||||
self.__lock.lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn guard_lock<'a, T>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
|
||||
&guard.__lock.lock
|
||||
}
|
||||
|
||||
pub fn guard_poison<'a, T>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag {
|
||||
&guard.__lock.poison
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use prelude::*;
|
||||
|
|
|
@ -53,18 +53,22 @@ pub struct Guard {
|
|||
/// is held. The precise semantics for when a lock is poisoned is documented on
|
||||
/// each lock, but once a lock is poisoned then all future acquisitions will
|
||||
/// return this error.
|
||||
#[stable]
|
||||
pub struct PoisonError<T> {
|
||||
guard: T,
|
||||
}
|
||||
|
||||
/// An enumeration of possible errors which can occur while calling the
|
||||
/// `try_lock` method.
|
||||
#[stable]
|
||||
pub enum TryLockError<T> {
|
||||
/// The lock could not be acquired because another task failed while holding
|
||||
/// the lock.
|
||||
#[stable]
|
||||
Poisoned(PoisonError<T>),
|
||||
/// The lock could not be acquired at this time because the operation would
|
||||
/// otherwise block.
|
||||
#[stable]
|
||||
WouldBlock,
|
||||
}
|
||||
|
||||
|
@ -75,6 +79,7 @@ pub enum TryLockError<T> {
|
|||
/// that the primitive was poisoned. Note that the `Err` variant *also* carries
|
||||
/// the associated guard, and it can be acquired through the `into_inner`
|
||||
/// method.
|
||||
#[stable]
|
||||
pub type LockResult<Guard> = Result<Guard, PoisonError<Guard>>;
|
||||
|
||||
/// A type alias for the result of a nonblocking locking method.
|
||||
|
@ -82,6 +87,7 @@ pub type LockResult<Guard> = Result<Guard, PoisonError<Guard>>;
|
|||
/// For more information, see `LockResult`. A `TryLockResult` doesn't
|
||||
/// necessarily hold the associated guard in the `Err` type as the lock may not
|
||||
/// have been acquired for other reasons.
|
||||
#[stable]
|
||||
pub type TryLockResult<Guard> = Result<Guard, TryLockError<Guard>>;
|
||||
|
||||
impl<T> fmt::Show for PoisonError<T> {
|
||||
|
@ -93,6 +99,7 @@ impl<T> fmt::Show for PoisonError<T> {
|
|||
impl<T> PoisonError<T> {
|
||||
/// Consumes this error indicating that a lock is poisoned, returning the
|
||||
/// underlying guard to allow access regardless.
|
||||
#[stable]
|
||||
pub fn into_guard(self) -> T { self.guard }
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ use sys_common::rwlock as sys;
|
|||
/// assert_eq!(*w, 6);
|
||||
/// } // write lock is dropped here
|
||||
/// ```
|
||||
#[stable]
|
||||
pub struct RWLock<T> {
|
||||
inner: Box<StaticRWLock>,
|
||||
data: UnsafeCell<T>,
|
||||
|
@ -88,6 +89,7 @@ unsafe impl<T> Sync for RWLock<T> {}
|
|||
/// }
|
||||
/// unsafe { LOCK.destroy() } // free all resources
|
||||
/// ```
|
||||
#[unstable = "may be merged with RWLock in the future"]
|
||||
pub struct StaticRWLock {
|
||||
lock: sys::RWLock,
|
||||
poison: poison::Flag,
|
||||
|
@ -97,6 +99,7 @@ unsafe impl Send for StaticRWLock {}
|
|||
unsafe impl Sync for StaticRWLock {}
|
||||
|
||||
/// Constant initialization for a statically-initialized rwlock.
|
||||
#[unstable = "may be merged with RWLock in the future"]
|
||||
pub const RWLOCK_INIT: StaticRWLock = StaticRWLock {
|
||||
lock: sys::RWLOCK_INIT,
|
||||
poison: poison::FLAG_INIT,
|
||||
|
@ -105,49 +108,27 @@ pub const RWLOCK_INIT: StaticRWLock = StaticRWLock {
|
|||
/// RAII structure used to release the shared read access of a lock when
|
||||
/// dropped.
|
||||
#[must_use]
|
||||
#[stable]
|
||||
pub struct RWLockReadGuard<'a, T: 'a> {
|
||||
__inner: ReadGuard<'a, RWLock<T>>,
|
||||
__lock: &'a StaticRWLock,
|
||||
__data: &'a UnsafeCell<T>,
|
||||
__marker: marker::NoSend,
|
||||
}
|
||||
|
||||
/// RAII structure used to release the exclusive write access of a lock when
|
||||
/// dropped.
|
||||
#[must_use]
|
||||
#[stable]
|
||||
pub struct RWLockWriteGuard<'a, T: 'a> {
|
||||
__inner: WriteGuard<'a, RWLock<T>>,
|
||||
}
|
||||
|
||||
/// RAII structure used to release the shared read access of a lock when
|
||||
/// dropped.
|
||||
#[must_use]
|
||||
pub struct StaticRWLockReadGuard {
|
||||
_inner: ReadGuard<'static, StaticRWLock>,
|
||||
}
|
||||
|
||||
/// RAII structure used to release the exclusive write access of a lock when
|
||||
/// dropped.
|
||||
#[must_use]
|
||||
pub struct StaticRWLockWriteGuard {
|
||||
_inner: WriteGuard<'static, StaticRWLock>,
|
||||
}
|
||||
|
||||
struct ReadGuard<'a, T: 'a> {
|
||||
inner: &'a T,
|
||||
marker: marker::NoSend, // even if 'a == static, cannot send
|
||||
}
|
||||
|
||||
struct WriteGuard<'a, T: 'a> {
|
||||
inner: &'a T,
|
||||
poison: poison::Guard,
|
||||
marker: marker::NoSend, // even if 'a == static, cannot send
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
trait AsStaticRWLock {
|
||||
fn as_static_rwlock(&self) -> &StaticRWLock;
|
||||
__lock: &'a StaticRWLock,
|
||||
__data: &'a UnsafeCell<T>,
|
||||
__poison: poison::Guard,
|
||||
__marker: marker::NoSend,
|
||||
}
|
||||
|
||||
impl<T: Send + Sync> RWLock<T> {
|
||||
/// Creates a new instance of an RWLock which is unlocked and read to go.
|
||||
#[stable]
|
||||
pub fn new(t: T) -> RWLock<T> {
|
||||
RWLock { inner: box RWLOCK_INIT, data: UnsafeCell::new(t) }
|
||||
}
|
||||
|
@ -170,9 +151,10 @@ impl<T: Send + Sync> RWLock<T> {
|
|||
/// is poisoned whenever a writer panics while holding an exclusive lock.
|
||||
/// The failure will occur immediately after the lock has been acquired.
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn read(&self) -> LockResult<RWLockReadGuard<T>> {
|
||||
unsafe { self.inner.lock.read() }
|
||||
RWLockReadGuard::new(self)
|
||||
RWLockReadGuard::new(&*self.inner, &self.data)
|
||||
}
|
||||
|
||||
/// Attempt to acquire this lock with shared read access.
|
||||
|
@ -191,9 +173,10 @@ impl<T: Send + Sync> RWLock<T> {
|
|||
/// error will only be returned if the lock would have otherwise been
|
||||
/// acquired.
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn try_read(&self) -> TryLockResult<RWLockReadGuard<T>> {
|
||||
if unsafe { self.inner.lock.try_read() } {
|
||||
Ok(try!(RWLockReadGuard::new(self)))
|
||||
Ok(try!(RWLockReadGuard::new(&*self.inner, &self.data)))
|
||||
} else {
|
||||
Err(TryLockError::WouldBlock)
|
||||
}
|
||||
|
@ -214,9 +197,10 @@ impl<T: Send + Sync> RWLock<T> {
|
|||
/// is poisoned whenever a writer panics while holding an exclusive lock.
|
||||
/// An error will be returned when the lock is acquired.
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn write(&self) -> LockResult<RWLockWriteGuard<T>> {
|
||||
unsafe { self.inner.lock.write() }
|
||||
RWLockWriteGuard::new(self)
|
||||
RWLockWriteGuard::new(&*self.inner, &self.data)
|
||||
}
|
||||
|
||||
/// Attempt to lock this rwlock with exclusive write access.
|
||||
|
@ -232,9 +216,10 @@ impl<T: Send + Sync> RWLock<T> {
|
|||
/// error will only be returned if the lock would have otherwise been
|
||||
/// acquired.
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn try_write(&self) -> TryLockResult<RWLockWriteGuard<T>> {
|
||||
if unsafe { self.inner.lock.try_read() } {
|
||||
Ok(try!(RWLockWriteGuard::new(self)))
|
||||
Ok(try!(RWLockWriteGuard::new(&*self.inner, &self.data)))
|
||||
} else {
|
||||
Err(TryLockError::WouldBlock)
|
||||
}
|
||||
|
@ -248,24 +233,29 @@ impl<T> Drop for RWLock<T> {
|
|||
}
|
||||
}
|
||||
|
||||
static DUMMY: UnsafeCell<()> = UnsafeCell { value: () };
|
||||
|
||||
impl StaticRWLock {
|
||||
/// 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<StaticRWLockReadGuard> {
|
||||
#[unstable = "may be merged with RWLock in the future"]
|
||||
pub fn read(&'static self) -> LockResult<RWLockReadGuard<'static, ()>> {
|
||||
unsafe { self.lock.read() }
|
||||
StaticRWLockReadGuard::new(self)
|
||||
RWLockReadGuard::new(self, &DUMMY)
|
||||
}
|
||||
|
||||
/// Attempt to acquire this lock with shared read access.
|
||||
///
|
||||
/// See `RWLock::try_read`.
|
||||
#[inline]
|
||||
pub fn try_read(&'static self) -> TryLockResult<StaticRWLockReadGuard> {
|
||||
#[unstable = "may be merged with RWLock in the future"]
|
||||
pub fn try_read(&'static self)
|
||||
-> TryLockResult<RWLockReadGuard<'static, ()>> {
|
||||
if unsafe { self.lock.try_read() } {
|
||||
Ok(try!(StaticRWLockReadGuard::new(self)))
|
||||
Ok(try!(RWLockReadGuard::new(self, &DUMMY)))
|
||||
} else {
|
||||
Err(TryLockError::WouldBlock)
|
||||
}
|
||||
|
@ -276,18 +266,21 @@ impl StaticRWLock {
|
|||
///
|
||||
/// See `RWLock::write`.
|
||||
#[inline]
|
||||
pub fn write(&'static self) -> LockResult<StaticRWLockWriteGuard> {
|
||||
#[unstable = "may be merged with RWLock in the future"]
|
||||
pub fn write(&'static self) -> LockResult<RWLockWriteGuard<'static, ()>> {
|
||||
unsafe { self.lock.write() }
|
||||
StaticRWLockWriteGuard::new(self)
|
||||
RWLockWriteGuard::new(self, &DUMMY)
|
||||
}
|
||||
|
||||
/// Attempt to lock this rwlock with exclusive write access.
|
||||
///
|
||||
/// See `RWLock::try_write`.
|
||||
#[inline]
|
||||
pub fn try_write(&'static self) -> TryLockResult<StaticRWLockWriteGuard> {
|
||||
#[unstable = "may be merged with RWLock in the future"]
|
||||
pub fn try_write(&'static self)
|
||||
-> TryLockResult<RWLockWriteGuard<'static, ()>> {
|
||||
if unsafe { self.lock.try_write() } {
|
||||
Ok(try!(StaticRWLockWriteGuard::new(self)))
|
||||
Ok(try!(RWLockWriteGuard::new(self, &DUMMY)))
|
||||
} else {
|
||||
Err(TryLockError::WouldBlock)
|
||||
}
|
||||
|
@ -299,93 +292,62 @@ impl StaticRWLock {
|
|||
/// 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.
|
||||
#[unstable = "may be merged with RWLock in the future"]
|
||||
pub unsafe fn destroy(&'static self) {
|
||||
self.lock.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'rwlock, T> RWLockReadGuard<'rwlock, T> {
|
||||
fn new(lock: &RWLock<T>) -> LockResult<RWLockReadGuard<T>> {
|
||||
poison::map_result(ReadGuard::new(lock), |guard| {
|
||||
RWLockReadGuard { __inner: guard }
|
||||
fn new(lock: &'rwlock StaticRWLock, data: &'rwlock UnsafeCell<T>)
|
||||
-> LockResult<RWLockReadGuard<'rwlock, T>> {
|
||||
poison::map_result(lock.poison.borrow(), |_| {
|
||||
RWLockReadGuard {
|
||||
__lock: lock,
|
||||
__data: data,
|
||||
__marker: marker::NoSend,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
impl<'rwlock, T> RWLockWriteGuard<'rwlock, T> {
|
||||
fn new(lock: &RWLock<T>) -> LockResult<RWLockWriteGuard<T>> {
|
||||
poison::map_result(WriteGuard::new(lock), |guard| {
|
||||
RWLockWriteGuard { __inner: guard }
|
||||
fn new(lock: &'rwlock StaticRWLock, data: &'rwlock UnsafeCell<T>)
|
||||
-> LockResult<RWLockWriteGuard<'rwlock, T>> {
|
||||
poison::map_result(lock.poison.borrow(), |guard| {
|
||||
RWLockWriteGuard {
|
||||
__lock: lock,
|
||||
__data: data,
|
||||
__poison: guard,
|
||||
__marker: marker::NoSend,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'rwlock, T> Deref<T> for RWLockReadGuard<'rwlock, T> {
|
||||
fn deref(&self) -> &T { unsafe { &*self.__inner.inner.data.get() } }
|
||||
fn deref(&self) -> &T { unsafe { &*self.__data.get() } }
|
||||
}
|
||||
impl<'rwlock, T> Deref<T> for RWLockWriteGuard<'rwlock, T> {
|
||||
fn deref(&self) -> &T { unsafe { &*self.__inner.inner.data.get() } }
|
||||
fn deref(&self) -> &T { unsafe { &*self.__data.get() } }
|
||||
}
|
||||
impl<'rwlock, T> DerefMut<T> for RWLockWriteGuard<'rwlock, T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
unsafe { &mut *self.__inner.inner.data.get() }
|
||||
}
|
||||
}
|
||||
|
||||
impl StaticRWLockReadGuard {
|
||||
#[inline]
|
||||
fn new(lock: &'static StaticRWLock) -> LockResult<StaticRWLockReadGuard> {
|
||||
poison::map_result(ReadGuard::new(lock), |guard| {
|
||||
StaticRWLockReadGuard { _inner: guard }
|
||||
})
|
||||
}
|
||||
}
|
||||
impl StaticRWLockWriteGuard {
|
||||
#[inline]
|
||||
fn new(lock: &'static StaticRWLock) -> LockResult<StaticRWLockWriteGuard> {
|
||||
poison::map_result(WriteGuard::new(lock), |guard| {
|
||||
StaticRWLockWriteGuard { _inner: guard }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsStaticRWLock for RWLock<T> {
|
||||
#[inline]
|
||||
fn as_static_rwlock(&self) -> &StaticRWLock { &*self.inner }
|
||||
}
|
||||
impl AsStaticRWLock for StaticRWLock {
|
||||
#[inline]
|
||||
fn as_static_rwlock(&self) -> &StaticRWLock { self }
|
||||
}
|
||||
|
||||
impl<'a, T: AsStaticRWLock> ReadGuard<'a, T> {
|
||||
fn new(t: &'a T) -> LockResult<ReadGuard<'a, T>> {
|
||||
poison::map_result(t.as_static_rwlock().poison.borrow(), |_| {
|
||||
ReadGuard { inner: t, marker: marker::NoSend }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: AsStaticRWLock> WriteGuard<'a, T> {
|
||||
fn new(t: &'a T) -> LockResult<WriteGuard<'a, T>> {
|
||||
poison::map_result(t.as_static_rwlock().poison.borrow(), |guard| {
|
||||
WriteGuard { inner: t, marker: marker::NoSend, poison: guard }
|
||||
})
|
||||
unsafe { &mut *self.__data.get() }
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl<'a, T: AsStaticRWLock> Drop for ReadGuard<'a, T> {
|
||||
impl<'a, T> Drop for RWLockReadGuard<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { self.inner.as_static_rwlock().lock.read_unlock(); }
|
||||
unsafe { self.__lock.lock.read_unlock(); }
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl<'a, T: AsStaticRWLock> Drop for WriteGuard<'a, T> {
|
||||
impl<'a, T> Drop for RWLockWriteGuard<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
let inner = self.inner.as_static_rwlock();
|
||||
inner.poison.done(&self.poison);
|
||||
unsafe { inner.lock.write_unlock(); }
|
||||
self.__lock.poison.done(&self.__poison);
|
||||
unsafe { self.__lock.lock.write_unlock(); }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue