]> git.lizzy.rs Git - rust.git/blob - library/std/src/sys_common/remutex.rs
4f19bbc467f33d19b47d70a7fc320562d58506f5
[rust.git] / library / std / src / sys_common / remutex.rs
1 use crate::fmt;
2 use crate::marker;
3 use crate::ops::Deref;
4 use crate::panic::{RefUnwindSafe, UnwindSafe};
5 use crate::sys::mutex as sys;
6
7 /// A re-entrant mutual exclusion
8 ///
9 /// This mutex will block *other* threads waiting for the lock to become
10 /// available. The thread which has already locked the mutex can lock it
11 /// multiple times without blocking, preventing a common source of deadlocks.
12 pub struct ReentrantMutex<T> {
13     inner: sys::ReentrantMutex,
14     data: T,
15 }
16
17 unsafe impl<T: Send> Send for ReentrantMutex<T> {}
18 unsafe impl<T: Send> Sync for ReentrantMutex<T> {}
19
20 impl<T> UnwindSafe for ReentrantMutex<T> {}
21 impl<T> RefUnwindSafe for ReentrantMutex<T> {}
22
23 /// An RAII implementation of a "scoped lock" of a mutex. When this structure is
24 /// dropped (falls out of scope), the lock will be unlocked.
25 ///
26 /// The data protected by the mutex can be accessed through this guard via its
27 /// Deref implementation.
28 ///
29 /// # Mutability
30 ///
31 /// Unlike `MutexGuard`, `ReentrantMutexGuard` does not implement `DerefMut`,
32 /// because implementation of the trait would violate Rust’s reference aliasing
33 /// rules. Use interior mutability (usually `RefCell`) in order to mutate the
34 /// guarded data.
35 #[must_use = "if unused the ReentrantMutex will immediately unlock"]
36 pub struct ReentrantMutexGuard<'a, T: 'a> {
37     // funny underscores due to how Deref currently works (it disregards field
38     // privacy).
39     __lock: &'a ReentrantMutex<T>,
40 }
41
42 impl<T> !marker::Send for ReentrantMutexGuard<'_, T> {}
43
44 impl<T> ReentrantMutex<T> {
45     /// Creates a new reentrant mutex in an unlocked state.
46     ///
47     /// # Unsafety
48     ///
49     /// This function is unsafe because it is required that `init` is called
50     /// once this mutex is in its final resting place, and only then are the
51     /// lock/unlock methods safe.
52     pub const unsafe fn new(t: T) -> ReentrantMutex<T> {
53         ReentrantMutex { inner: sys::ReentrantMutex::uninitialized(), data: t }
54     }
55
56     /// Initializes this mutex so it's ready for use.
57     ///
58     /// # Unsafety
59     ///
60     /// Unsafe to call more than once, and must be called after this will no
61     /// longer move in memory.
62     pub unsafe fn init(&self) {
63         self.inner.init();
64     }
65
66     /// Acquires a mutex, blocking the current thread until it is able to do so.
67     ///
68     /// This function will block the caller until it is available to acquire the mutex.
69     /// Upon returning, the thread is the only thread with the mutex held. When the thread
70     /// calling this method already holds the lock, the call shall succeed without
71     /// blocking.
72     ///
73     /// # Errors
74     ///
75     /// If another user of this mutex panicked while holding the mutex, then
76     /// this call will return failure if the mutex would otherwise be
77     /// acquired.
78     pub fn lock(&self) -> ReentrantMutexGuard<'_, T> {
79         unsafe { self.inner.lock() }
80         ReentrantMutexGuard::new(&self)
81     }
82
83     /// Attempts to acquire this lock.
84     ///
85     /// If the lock could not be acquired at this time, then `Err` is returned.
86     /// Otherwise, an RAII guard is returned.
87     ///
88     /// This function does not block.
89     ///
90     /// # Errors
91     ///
92     /// If another user of this mutex panicked while holding the mutex, then
93     /// this call will return failure if the mutex would otherwise be
94     /// acquired.
95     pub fn try_lock(&self) -> Option<ReentrantMutexGuard<'_, T>> {
96         if unsafe { self.inner.try_lock() } { Some(ReentrantMutexGuard::new(&self)) } else { None }
97     }
98 }
99
100 impl<T> Drop for ReentrantMutex<T> {
101     fn drop(&mut self) {
102         // This is actually safe b/c we know that there is no further usage of
103         // this mutex (it's up to the user to arrange for a mutex to get
104         // dropped, that's not our job)
105         unsafe { self.inner.destroy() }
106     }
107 }
108
109 impl<T: fmt::Debug + 'static> fmt::Debug for ReentrantMutex<T> {
110     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111         match self.try_lock() {
112             Some(guard) => f.debug_struct("ReentrantMutex").field("data", &*guard).finish(),
113             None => {
114                 struct LockedPlaceholder;
115                 impl fmt::Debug for LockedPlaceholder {
116                     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117                         f.write_str("<locked>")
118                     }
119                 }
120
121                 f.debug_struct("ReentrantMutex").field("data", &LockedPlaceholder).finish()
122             }
123         }
124     }
125 }
126
127 impl<'mutex, T> ReentrantMutexGuard<'mutex, T> {
128     fn new(lock: &'mutex ReentrantMutex<T>) -> ReentrantMutexGuard<'mutex, T> {
129         ReentrantMutexGuard { __lock: lock }
130     }
131 }
132
133 impl<T> Deref for ReentrantMutexGuard<'_, T> {
134     type Target = T;
135
136     fn deref(&self) -> &T {
137         &self.__lock.data
138     }
139 }
140
141 impl<T> Drop for ReentrantMutexGuard<'_, T> {
142     #[inline]
143     fn drop(&mut self) {
144         unsafe {
145             self.__lock.inner.unlock();
146         }
147     }
148 }
149
150 #[cfg(all(test, not(target_os = "emscripten")))]
151 mod tests {
152     use crate::cell::RefCell;
153     use crate::sync::Arc;
154     use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
155     use crate::thread;
156
157     #[test]
158     fn smoke() {
159         let m = unsafe {
160             let m = ReentrantMutex::new(());
161             m.init();
162             m
163         };
164         {
165             let a = m.lock();
166             {
167                 let b = m.lock();
168                 {
169                     let c = m.lock();
170                     assert_eq!(*c, ());
171                 }
172                 assert_eq!(*b, ());
173             }
174             assert_eq!(*a, ());
175         }
176     }
177
178     #[test]
179     fn is_mutex() {
180         let m = unsafe {
181             let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
182             m.init();
183             m
184         };
185         let m2 = m.clone();
186         let lock = m.lock();
187         let child = thread::spawn(move || {
188             let lock = m2.lock();
189             assert_eq!(*lock.borrow(), 4950);
190         });
191         for i in 0..100 {
192             let lock = m.lock();
193             *lock.borrow_mut() += i;
194         }
195         drop(lock);
196         child.join().unwrap();
197     }
198
199     #[test]
200     fn trylock_works() {
201         let m = unsafe {
202             let m = Arc::new(ReentrantMutex::new(()));
203             m.init();
204             m
205         };
206         let m2 = m.clone();
207         let _lock = m.try_lock();
208         let _lock2 = m.try_lock();
209         thread::spawn(move || {
210             let lock = m2.try_lock();
211             assert!(lock.is_none());
212         })
213         .join()
214         .unwrap();
215         let _lock3 = m.try_lock();
216     }
217
218     pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell<u32>>);
219     impl Drop for Answer<'_> {
220         fn drop(&mut self) {
221             *self.0.borrow_mut() = 42;
222         }
223     }
224 }