use crate::ops::Deref;
use crate::panic::{RefUnwindSafe, UnwindSafe};
use crate::sys::mutex as sys;
-use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult};
/// A re-entrant mutual exclusion
///
/// available. The thread which has already locked the mutex can lock it
/// multiple times without blocking, preventing a common source of deadlocks.
pub struct ReentrantMutex<T> {
- inner: Box<sys::ReentrantMutex>,
- poison: poison::Flag,
+ inner: sys::ReentrantMutex,
data: T,
}
// funny underscores due to how Deref currently works (it disregards field
// privacy).
__lock: &'a ReentrantMutex<T>,
- __poison: poison::Guard,
}
impl<T> !marker::Send for ReentrantMutexGuard<'_, T> {}
impl<T> ReentrantMutex<T> {
/// Creates a new reentrant mutex in an unlocked state.
- pub fn new(t: T) -> ReentrantMutex<T> {
- unsafe {
- let mut mutex = ReentrantMutex {
- inner: box sys::ReentrantMutex::uninitialized(),
- poison: poison::Flag::new(),
- data: t,
- };
- mutex.inner.init();
- mutex
- }
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe because it is required that `init` is called
+ /// once this mutex is in its final resting place, and only then are the
+ /// lock/unlock methods safe.
+ pub const unsafe fn new(t: T) -> ReentrantMutex<T> {
+ ReentrantMutex { inner: sys::ReentrantMutex::uninitialized(), data: t }
+ }
+
+ /// Initializes this mutex so it's ready for use.
+ ///
+ /// # Unsafety
+ ///
+ /// Unsafe to call more than once, and must be called after this will no
+ /// longer move in memory.
+ pub unsafe fn init(&self) {
+ self.inner.init();
}
/// Acquires a mutex, blocking the current thread until it is able to do so.
/// If another user of this mutex panicked while holding the mutex, then
/// this call will return failure if the mutex would otherwise be
/// acquired.
- pub fn lock(&self) -> LockResult<ReentrantMutexGuard<'_, T>> {
+ pub fn lock(&self) -> ReentrantMutexGuard<'_, T> {
unsafe { self.inner.lock() }
ReentrantMutexGuard::new(&self)
}
/// If another user of this mutex panicked while holding the mutex, then
/// this call will return failure if the mutex would otherwise be
/// acquired.
- pub fn try_lock(&self) -> TryLockResult<ReentrantMutexGuard<'_, T>> {
- if unsafe { self.inner.try_lock() } {
- Ok(ReentrantMutexGuard::new(&self)?)
- } else {
- Err(TryLockError::WouldBlock)
- }
+ pub fn try_lock(&self) -> Option<ReentrantMutexGuard<'_, T>> {
+ if unsafe { self.inner.try_lock() } { Some(ReentrantMutexGuard::new(&self)) } else { None }
}
}
impl<T: fmt::Debug + 'static> fmt::Debug for ReentrantMutex<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.try_lock() {
- Ok(guard) => f.debug_struct("ReentrantMutex").field("data", &*guard).finish(),
- Err(TryLockError::Poisoned(err)) => {
- f.debug_struct("ReentrantMutex").field("data", &**err.get_ref()).finish()
- }
- Err(TryLockError::WouldBlock) => {
+ Some(guard) => f.debug_struct("ReentrantMutex").field("data", &*guard).finish(),
+ None => {
struct LockedPlaceholder;
impl fmt::Debug for LockedPlaceholder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
impl<'mutex, T> ReentrantMutexGuard<'mutex, T> {
- fn new(lock: &'mutex ReentrantMutex<T>) -> LockResult<ReentrantMutexGuard<'mutex, T>> {
- poison::map_result(lock.poison.borrow(), |guard| ReentrantMutexGuard {
- __lock: lock,
- __poison: guard,
- })
+ fn new(lock: &'mutex ReentrantMutex<T>) -> ReentrantMutexGuard<'mutex, T> {
+ ReentrantMutexGuard { __lock: lock }
}
}
#[inline]
fn drop(&mut self) {
unsafe {
- self.__lock.poison.done(&self.__poison);
self.__lock.inner.unlock();
}
}
#[test]
fn smoke() {
- let m = ReentrantMutex::new(());
+ let m = unsafe {
+ let m = ReentrantMutex::new(());
+ m.init();
+ m
+ };
{
- let a = m.lock().unwrap();
+ let a = m.lock();
{
- let b = m.lock().unwrap();
+ let b = m.lock();
{
- let c = m.lock().unwrap();
+ let c = m.lock();
assert_eq!(*c, ());
}
assert_eq!(*b, ());
#[test]
fn is_mutex() {
- let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
+ let m = unsafe {
+ let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
+ m.init();
+ m
+ };
let m2 = m.clone();
- let lock = m.lock().unwrap();
+ let lock = m.lock();
let child = thread::spawn(move || {
- let lock = m2.lock().unwrap();
+ let lock = m2.lock();
assert_eq!(*lock.borrow(), 4950);
});
for i in 0..100 {
- let lock = m.lock().unwrap();
+ let lock = m.lock();
*lock.borrow_mut() += i;
}
drop(lock);
#[test]
fn trylock_works() {
- let m = Arc::new(ReentrantMutex::new(()));
+ let m = unsafe {
+ let m = Arc::new(ReentrantMutex::new(()));
+ m.init();
+ m
+ };
let m2 = m.clone();
- let _lock = m.try_lock().unwrap();
- let _lock2 = m.try_lock().unwrap();
+ let _lock = m.try_lock();
+ let _lock2 = m.try_lock();
thread::spawn(move || {
let lock = m2.try_lock();
- assert!(lock.is_err());
+ assert!(lock.is_none());
})
.join()
.unwrap();
- let _lock3 = m.try_lock().unwrap();
+ let _lock3 = m.try_lock();
}
pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell<u32>>);
*self.0.borrow_mut() = 42;
}
}
-
- #[test]
- fn poison_works() {
- let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
- let mc = m.clone();
- let result = thread::spawn(move || {
- let lock = mc.lock().unwrap();
- *lock.borrow_mut() = 1;
- let lock2 = mc.lock().unwrap();
- *lock.borrow_mut() = 2;
- let _answer = Answer(lock2);
- panic!("What the answer to my lifetimes dilemma is?");
- })
- .join();
- assert!(result.is_err());
- let r = m.lock().err().unwrap().into_inner();
- assert_eq!(*r.borrow(), 42);
- }
}