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:
Alex Crichton 2014-12-29 10:01:38 -08:00
parent 76e5ed655c
commit 35e63e3827
5 changed files with 158 additions and 236 deletions

View File

@ -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()
}

View File

@ -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,
}

View File

@ -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 }
})
}
}
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() }
}
}
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,
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<'mutex, T> Deref<T> for MutexGuard<'mutex, T> {
fn deref<'a>(&'a self) -> &'a T {
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.__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::*;

View File

@ -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 }
}

View File

@ -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(); }
}
}