1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
16 use sys_common
::poison
::{self, TryLockError, TryLockResult, LockResult}
;
17 use sys
::mutex
as sys
;
19 /// A re-entrant mutual exclusion
21 /// This mutex will block *other* threads waiting for the lock to become
22 /// available. The thread which has already locked the mutex can lock it
23 /// multiple times without blocking, preventing a common source of deadlocks.
24 pub struct ReentrantMutex
<T
> {
25 inner
: Box
<sys
::ReentrantMutex
>,
30 unsafe impl<T
: Send
> Send
for ReentrantMutex
<T
> {}
31 unsafe impl<T
: Send
> Sync
for ReentrantMutex
<T
> {}
34 /// An RAII implementation of a "scoped lock" of a mutex. When this structure is
35 /// dropped (falls out of scope), the lock will be unlocked.
37 /// The data protected by the mutex can be accessed through this guard via its
38 /// Deref implementation.
42 /// Unlike `MutexGuard`, `ReentrantMutexGuard` does not implement `DerefMut`,
43 /// because implementation of the trait would violate Rust’s reference aliasing
44 /// rules. Use interior mutability (usually `RefCell`) in order to mutate the
47 pub struct ReentrantMutexGuard
<'a
, T
: 'a
> {
48 // funny underscores due to how Deref currently works (it disregards field
50 __lock
: &'a ReentrantMutex
<T
>,
51 __poison
: poison
::Guard
,
54 impl<'a
, T
> !marker
::Send
for ReentrantMutexGuard
<'a
, T
> {}
57 impl<T
> ReentrantMutex
<T
> {
58 /// Creates a new reentrant mutex in an unlocked state.
59 pub fn new(t
: T
) -> ReentrantMutex
<T
> {
61 let mut mutex
= ReentrantMutex
{
62 inner
: box sys
::ReentrantMutex
::uninitialized(),
63 poison
: poison
::Flag
::new(),
71 /// Acquires a mutex, blocking the current thread until it is able to do so.
73 /// This function will block the caller until it is available to acquire the mutex.
74 /// Upon returning, the thread is the only thread with the mutex held. When the thread
75 /// calling this method already holds the lock, the call shall succeed without
80 /// If another user of this mutex panicked while holding the mutex, then
81 /// this call will return failure if the mutex would otherwise be
83 pub fn lock(&self) -> LockResult
<ReentrantMutexGuard
<T
>> {
84 unsafe { self.inner.lock() }
85 ReentrantMutexGuard
::new(&self)
88 /// Attempts to acquire this lock.
90 /// If the lock could not be acquired at this time, then `Err` is returned.
91 /// Otherwise, an RAII guard is returned.
93 /// This function does not block.
97 /// If another user of this mutex panicked while holding the mutex, then
98 /// this call will return failure if the mutex would otherwise be
100 pub fn try_lock(&self) -> TryLockResult
<ReentrantMutexGuard
<T
>> {
101 if unsafe { self.inner.try_lock() }
{
102 Ok(ReentrantMutexGuard
::new(&self)?
)
104 Err(TryLockError
::WouldBlock
)
109 impl<T
> Drop
for ReentrantMutex
<T
> {
111 // This is actually safe b/c we know that there is no further usage of
112 // this mutex (it's up to the user to arrange for a mutex to get
113 // dropped, that's not our job)
114 unsafe { self.inner.destroy() }
118 impl<T
: fmt
::Debug
+ '
static> fmt
::Debug
for ReentrantMutex
<T
> {
119 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
120 match self.try_lock() {
121 Ok(guard
) => write
!(f
, "ReentrantMutex {{ data: {:?} }}", &*guard
),
122 Err(TryLockError
::Poisoned(err
)) => {
123 write
!(f
, "ReentrantMutex {{ data: Poisoned({:?}) }}", &**err
.get_ref())
125 Err(TryLockError
::WouldBlock
) => write
!(f
, "ReentrantMutex {{ <locked> }}")
130 impl<'mutex
, T
> ReentrantMutexGuard
<'mutex
, T
> {
131 fn new(lock
: &'mutex ReentrantMutex
<T
>)
132 -> LockResult
<ReentrantMutexGuard
<'mutex
, T
>> {
133 poison
::map_result(lock
.poison
.borrow(), |guard
| {
134 ReentrantMutexGuard
{
142 impl<'mutex
, T
> Deref
for ReentrantMutexGuard
<'mutex
, T
> {
145 fn deref(&self) -> &T
{
150 impl<'a
, T
> Drop
for ReentrantMutexGuard
<'a
, T
> {
154 self.__lock
.poison
.done(&self.__poison
);
155 self.__lock
.inner
.unlock();
164 use sys_common
::remutex
::{ReentrantMutex, ReentrantMutexGuard}
;
171 let m
= ReentrantMutex
::new(());
173 let a
= m
.lock().unwrap();
175 let b
= m
.lock().unwrap();
177 let c
= m
.lock().unwrap();
188 let m
= Arc
::new(ReentrantMutex
::new(RefCell
::new(0)));
190 let lock
= m
.lock().unwrap();
191 let child
= thread
::spawn(move || {
192 let lock
= m2
.lock().unwrap();
193 assert_eq
!(*lock
.borrow(), 4950);
196 let lock
= m
.lock().unwrap();
197 *lock
.borrow_mut() += i
;
200 child
.join().unwrap();
205 let m
= Arc
::new(ReentrantMutex
::new(()));
207 let _lock
= m
.try_lock().unwrap();
208 let _lock2
= m
.try_lock().unwrap();
209 thread
::spawn(move || {
210 let lock
= m2
.try_lock();
211 assert
!(lock
.is_err());
213 let _lock3
= m
.try_lock().unwrap();
216 pub struct Answer
<'a
>(pub ReentrantMutexGuard
<'a
, RefCell
<u32>>);
217 impl<'a
> Drop
for Answer
<'a
> {
219 *self.0.borrow_mut() = 42;
225 let m
= Arc
::new(ReentrantMutex
::new(RefCell
::new(0)));
227 let result
= thread
::spawn(move ||{
228 let lock
= mc
.lock().unwrap();
229 *lock
.borrow_mut() = 1;
230 let lock2
= mc
.lock().unwrap();
231 *lock
.borrow_mut() = 2;
232 let _answer
= Answer(lock2
);
233 panic
!("What the answer to my lifetimes dilemma is?");
235 assert
!(result
.is_err());
236 let r
= m
.lock().err().unwrap().into_inner();
237 assert_eq
!(*r
.borrow(), 42);