]>
Commit | Line | Data |
---|---|---|
1b1a35ee XL |
1 | #[cfg(all(test, not(target_os = "emscripten")))] |
2 | mod tests; | |
3 | ||
532ac7d7 XL |
4 | use crate::cell::UnsafeCell; |
5 | use crate::fmt; | |
6 | use crate::mem; | |
7 | use crate::ops::{Deref, DerefMut}; | |
8 | use crate::ptr; | |
9 | use crate::sys_common::mutex as sys; | |
dfeec247 | 10 | use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult}; |
1a4d82fc JJ |
11 | |
12 | /// A mutual exclusion primitive useful for protecting shared data | |
13 | /// | |
14 | /// This mutex will block threads waiting for the lock to become available. The | |
ea8adc8c | 15 | /// mutex can also be statically initialized or created via a [`new`] |
1a4d82fc JJ |
16 | /// constructor. Each mutex has a type parameter which represents the data that |
17 | /// it is protecting. The data can only be accessed through the RAII guards | |
ea8adc8c | 18 | /// returned from [`lock`] and [`try_lock`], which guarantees that the data is only |
1a4d82fc JJ |
19 | /// ever accessed when the mutex is locked. |
20 | /// | |
21 | /// # Poisoning | |
22 | /// | |
23 | /// The mutexes in this module implement a strategy called "poisoning" where a | |
24 | /// mutex is considered poisoned whenever a thread panics while holding the | |
cc61c64b | 25 | /// mutex. Once a mutex is poisoned, all other threads are unable to access the |
1a4d82fc JJ |
26 | /// data by default as it is likely tainted (some invariant is not being |
27 | /// upheld). | |
28 | /// | |
ea8adc8c XL |
29 | /// For a mutex, this means that the [`lock`] and [`try_lock`] methods return a |
30 | /// [`Result`] which indicates whether a mutex has been poisoned or not. Most | |
31 | /// usage of a mutex will simply [`unwrap()`] these results, propagating panics | |
1a4d82fc JJ |
32 | /// among threads to ensure that a possibly invalid invariant is not witnessed. |
33 | /// | |
34 | /// A poisoned mutex, however, does not prevent all access to the underlying | |
ea8adc8c | 35 | /// data. The [`PoisonError`] type has an [`into_inner`] method which will return |
1a4d82fc JJ |
36 | /// the guard that would have otherwise been returned on a successful lock. This |
37 | /// allows access to the data, despite the lock being poisoned. | |
38 | /// | |
3dfed10e XL |
39 | /// [`new`]: Self::new |
40 | /// [`lock`]: Self::lock | |
41 | /// [`try_lock`]: Self::try_lock | |
42 | /// [`unwrap()`]: Result::unwrap | |
43 | /// [`PoisonError`]: super::PoisonError | |
44 | /// [`into_inner`]: super::PoisonError::into_inner | |
ea8adc8c | 45 | /// |
1a4d82fc JJ |
46 | /// # Examples |
47 | /// | |
c34b1796 | 48 | /// ``` |
1a4d82fc | 49 | /// use std::sync::{Arc, Mutex}; |
85aaf69f | 50 | /// use std::thread; |
1a4d82fc JJ |
51 | /// use std::sync::mpsc::channel; |
52 | /// | |
c34b1796 | 53 | /// const N: usize = 10; |
1a4d82fc JJ |
54 | /// |
55 | /// // Spawn a few threads to increment a shared variable (non-atomically), and | |
56 | /// // let the main thread know once all increments are done. | |
57 | /// // | |
bd371182 | 58 | /// // Here we're using an Arc to share memory among threads, and the data inside |
1a4d82fc JJ |
59 | /// // the Arc is protected with a mutex. |
60 | /// let data = Arc::new(Mutex::new(0)); | |
61 | /// | |
62 | /// let (tx, rx) = channel(); | |
cc61c64b | 63 | /// for _ in 0..N { |
a1dfa0c6 | 64 | /// let (data, tx) = (Arc::clone(&data), tx.clone()); |
85aaf69f | 65 | /// thread::spawn(move || { |
92a42be0 | 66 | /// // The shared state can only be accessed once the lock is held. |
1a4d82fc JJ |
67 | /// // Our non-atomic increment is safe because we're the only thread |
68 | /// // which can access the shared state when the lock is held. | |
69 | /// // | |
70 | /// // We unwrap() the return value to assert that we are not expecting | |
bd371182 | 71 | /// // threads to ever fail while holding the lock. |
1a4d82fc JJ |
72 | /// let mut data = data.lock().unwrap(); |
73 | /// *data += 1; | |
74 | /// if *data == N { | |
75 | /// tx.send(()).unwrap(); | |
76 | /// } | |
77 | /// // the lock is unlocked here when `data` goes out of scope. | |
78 | /// }); | |
79 | /// } | |
80 | /// | |
81 | /// rx.recv().unwrap(); | |
82 | /// ``` | |
83 | /// | |
84 | /// To recover from a poisoned mutex: | |
85 | /// | |
c34b1796 | 86 | /// ``` |
1a4d82fc | 87 | /// use std::sync::{Arc, Mutex}; |
85aaf69f | 88 | /// use std::thread; |
1a4d82fc | 89 | /// |
85aaf69f | 90 | /// let lock = Arc::new(Mutex::new(0_u32)); |
1b1a35ee | 91 | /// let lock2 = Arc::clone(&lock); |
1a4d82fc | 92 | /// |
85aaf69f | 93 | /// let _ = thread::spawn(move || -> () { |
1a4d82fc JJ |
94 | /// // This thread will acquire the mutex first, unwrapping the result of |
95 | /// // `lock` because the lock has not been poisoned. | |
7453a54e | 96 | /// let _guard = lock2.lock().unwrap(); |
1a4d82fc JJ |
97 | /// |
98 | /// // This panic while holding the lock (`_guard` is in scope) will poison | |
99 | /// // the mutex. | |
100 | /// panic!(); | |
101 | /// }).join(); | |
102 | /// | |
103 | /// // The lock is poisoned by this point, but the returned result can be | |
104 | /// // pattern matched on to return the underlying guard on both branches. | |
105 | /// let mut guard = match lock.lock() { | |
106 | /// Ok(guard) => guard, | |
c34b1796 | 107 | /// Err(poisoned) => poisoned.into_inner(), |
1a4d82fc JJ |
108 | /// }; |
109 | /// | |
110 | /// *guard += 1; | |
111 | /// ``` | |
f035d41b XL |
112 | /// |
113 | /// It is sometimes necessary to manually drop the mutex guard to unlock it | |
114 | /// sooner than the end of the enclosing scope. | |
115 | /// | |
116 | /// ``` | |
117 | /// use std::sync::{Arc, Mutex}; | |
118 | /// use std::thread; | |
119 | /// | |
120 | /// const N: usize = 3; | |
121 | /// | |
122 | /// let data_mutex = Arc::new(Mutex::new(vec![1, 2, 3, 4])); | |
123 | /// let res_mutex = Arc::new(Mutex::new(0)); | |
124 | /// | |
125 | /// let mut threads = Vec::with_capacity(N); | |
126 | /// (0..N).for_each(|_| { | |
127 | /// let data_mutex_clone = Arc::clone(&data_mutex); | |
128 | /// let res_mutex_clone = Arc::clone(&res_mutex); | |
129 | /// | |
130 | /// threads.push(thread::spawn(move || { | |
131 | /// let mut data = data_mutex_clone.lock().unwrap(); | |
132 | /// // This is the result of some important and long-ish work. | |
133 | /// let result = data.iter().fold(0, |acc, x| acc + x * 2); | |
134 | /// data.push(result); | |
135 | /// drop(data); | |
136 | /// *res_mutex_clone.lock().unwrap() += result; | |
137 | /// })); | |
138 | /// }); | |
139 | /// | |
140 | /// let mut data = data_mutex.lock().unwrap(); | |
141 | /// // This is the result of some important and long-ish work. | |
142 | /// let result = data.iter().fold(0, |acc, x| acc + x * 2); | |
143 | /// data.push(result); | |
144 | /// // We drop the `data` explicitly because it's not necessary anymore and the | |
145 | /// // thread still has work to do. This allow other threads to start working on | |
146 | /// // the data immediately, without waiting for the rest of the unrelated work | |
147 | /// // to be done here. | |
148 | /// // | |
149 | /// // It's even more important here than in the threads because we `.join` the | |
150 | /// // threads after that. If we had not dropped the mutex guard, a thread could | |
151 | /// // be waiting forever for it, causing a deadlock. | |
152 | /// drop(data); | |
153 | /// // Here the mutex guard is not assigned to a variable and so, even if the | |
154 | /// // scope does not end after this line, the mutex is still released: there is | |
155 | /// // no deadlock. | |
156 | /// *res_mutex.lock().unwrap() += result; | |
157 | /// | |
158 | /// threads.into_iter().for_each(|thread| { | |
159 | /// thread | |
160 | /// .join() | |
161 | /// .expect("The thread creating or execution failed !") | |
162 | /// }); | |
163 | /// | |
164 | /// assert_eq!(*res_mutex.lock().unwrap(), 800); | |
165 | /// ``` | |
85aaf69f | 166 | #[stable(feature = "rust1", since = "1.0.0")] |
f9f354fc | 167 | #[cfg_attr(not(test), rustc_diagnostic_item = "mutex_type")] |
d9579d0f | 168 | pub struct Mutex<T: ?Sized> { |
1b1a35ee | 169 | inner: sys::MovableMutex, |
5bcae85e | 170 | poison: poison::Flag, |
1a4d82fc JJ |
171 | data: UnsafeCell<T>, |
172 | } | |
173 | ||
c34b1796 AL |
174 | // these are the only places where `T: Send` matters; all other |
175 | // functionality works fine on a single thread. | |
92a42be0 | 176 | #[stable(feature = "rust1", since = "1.0.0")] |
dfeec247 | 177 | unsafe impl<T: ?Sized + Send> Send for Mutex<T> {} |
92a42be0 | 178 | #[stable(feature = "rust1", since = "1.0.0")] |
dfeec247 | 179 | unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {} |
1a4d82fc | 180 | |
1a4d82fc JJ |
181 | /// An RAII implementation of a "scoped lock" of a mutex. When this structure is |
182 | /// dropped (falls out of scope), the lock will be unlocked. | |
183 | /// | |
cc61c64b | 184 | /// The data protected by the mutex can be accessed through this guard via its |
8bb4bdeb | 185 | /// [`Deref`] and [`DerefMut`] implementations. |
476ff2be | 186 | /// |
cc61c64b | 187 | /// This structure is created by the [`lock`] and [`try_lock`] methods on |
476ff2be SL |
188 | /// [`Mutex`]. |
189 | /// | |
3dfed10e XL |
190 | /// [`lock`]: Mutex::lock |
191 | /// [`try_lock`]: Mutex::try_lock | |
94b46f34 | 192 | #[must_use = "if unused the Mutex will immediately unlock"] |
85aaf69f | 193 | #[stable(feature = "rust1", since = "1.0.0")] |
d9579d0f | 194 | pub struct MutexGuard<'a, T: ?Sized + 'a> { |
60c5eb7d XL |
195 | lock: &'a Mutex<T>, |
196 | poison: poison::Guard, | |
1a4d82fc JJ |
197 | } |
198 | ||
92a42be0 | 199 | #[stable(feature = "rust1", since = "1.0.0")] |
dfeec247 | 200 | impl<T: ?Sized> !Send for MutexGuard<'_, T> {} |
7cac9316 | 201 | #[stable(feature = "mutexguard", since = "1.19.0")] |
dfeec247 | 202 | unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {} |
85aaf69f | 203 | |
c34b1796 | 204 | impl<T> Mutex<T> { |
1a4d82fc | 205 | /// Creates a new mutex in an unlocked state ready for use. |
32a655c1 SL |
206 | /// |
207 | /// # Examples | |
208 | /// | |
209 | /// ``` | |
210 | /// use std::sync::Mutex; | |
211 | /// | |
212 | /// let mutex = Mutex::new(0); | |
213 | /// ``` | |
85aaf69f | 214 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 215 | pub fn new(t: T) -> Mutex<T> { |
1b1a35ee XL |
216 | Mutex { |
217 | inner: sys::MovableMutex::new(), | |
5bcae85e | 218 | poison: poison::Flag::new(), |
1a4d82fc JJ |
219 | data: UnsafeCell::new(t), |
220 | } | |
221 | } | |
d9579d0f | 222 | } |
1a4d82fc | 223 | |
d9579d0f | 224 | impl<T: ?Sized> Mutex<T> { |
bd371182 | 225 | /// Acquires a mutex, blocking the current thread until it is able to do so. |
1a4d82fc | 226 | /// |
bd371182 | 227 | /// This function will block the local thread until it is available to acquire |
cc61c64b | 228 | /// the mutex. Upon returning, the thread is the only thread with the lock |
1a4d82fc JJ |
229 | /// held. An RAII guard is returned to allow scoped unlock of the lock. When |
230 | /// the guard goes out of scope, the mutex will be unlocked. | |
231 | /// | |
a7813a04 XL |
232 | /// The exact behavior on locking a mutex in the thread which already holds |
233 | /// the lock is left unspecified. However, this function will not return on | |
234 | /// the second call (it might panic or deadlock, for example). | |
235 | /// | |
7453a54e | 236 | /// # Errors |
1a4d82fc JJ |
237 | /// |
238 | /// If another user of this mutex panicked while holding the mutex, then | |
239 | /// this call will return an error once the mutex is acquired. | |
a7813a04 XL |
240 | /// |
241 | /// # Panics | |
242 | /// | |
243 | /// This function might panic when called if the lock is already held by | |
244 | /// the current thread. | |
32a655c1 SL |
245 | /// |
246 | /// # Examples | |
247 | /// | |
248 | /// ``` | |
249 | /// use std::sync::{Arc, Mutex}; | |
250 | /// use std::thread; | |
251 | /// | |
252 | /// let mutex = Arc::new(Mutex::new(0)); | |
1b1a35ee | 253 | /// let c_mutex = Arc::clone(&mutex); |
32a655c1 SL |
254 | /// |
255 | /// thread::spawn(move || { | |
256 | /// *c_mutex.lock().unwrap() = 10; | |
257 | /// }).join().expect("thread::spawn failed"); | |
258 | /// assert_eq!(*mutex.lock().unwrap(), 10); | |
259 | /// ``` | |
85aaf69f | 260 | #[stable(feature = "rust1", since = "1.0.0")] |
532ac7d7 | 261 | pub fn lock(&self) -> LockResult<MutexGuard<'_, T>> { |
7453a54e | 262 | unsafe { |
94b46f34 | 263 | self.inner.raw_lock(); |
5bcae85e | 264 | MutexGuard::new(self) |
7453a54e | 265 | } |
1a4d82fc JJ |
266 | } |
267 | ||
268 | /// Attempts to acquire this lock. | |
269 | /// | |
ea8adc8c | 270 | /// If the lock could not be acquired at this time, then [`Err`] is returned. |
1a4d82fc JJ |
271 | /// Otherwise, an RAII guard is returned. The lock will be unlocked when the |
272 | /// guard is dropped. | |
273 | /// | |
274 | /// This function does not block. | |
275 | /// | |
7453a54e | 276 | /// # Errors |
1a4d82fc JJ |
277 | /// |
278 | /// If another user of this mutex panicked while holding the mutex, then | |
279 | /// this call will return failure if the mutex would otherwise be | |
280 | /// acquired. | |
32a655c1 SL |
281 | /// |
282 | /// # Examples | |
283 | /// | |
284 | /// ``` | |
285 | /// use std::sync::{Arc, Mutex}; | |
286 | /// use std::thread; | |
287 | /// | |
288 | /// let mutex = Arc::new(Mutex::new(0)); | |
1b1a35ee | 289 | /// let c_mutex = Arc::clone(&mutex); |
32a655c1 SL |
290 | /// |
291 | /// thread::spawn(move || { | |
292 | /// let mut lock = c_mutex.try_lock(); | |
293 | /// if let Ok(ref mut mutex) = lock { | |
294 | /// **mutex = 10; | |
295 | /// } else { | |
296 | /// println!("try_lock failed"); | |
297 | /// } | |
298 | /// }).join().expect("thread::spawn failed"); | |
299 | /// assert_eq!(*mutex.lock().unwrap(), 10); | |
300 | /// ``` | |
85aaf69f | 301 | #[stable(feature = "rust1", since = "1.0.0")] |
532ac7d7 | 302 | pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T>> { |
7453a54e | 303 | unsafe { |
5bcae85e SL |
304 | if self.inner.try_lock() { |
305 | Ok(MutexGuard::new(self)?) | |
7453a54e SL |
306 | } else { |
307 | Err(TryLockError::WouldBlock) | |
308 | } | |
1a4d82fc JJ |
309 | } |
310 | } | |
85aaf69f | 311 | |
cc61c64b | 312 | /// Determines whether the mutex is poisoned. |
85aaf69f | 313 | /// |
cc61c64b | 314 | /// If another thread is active, the mutex can still become poisoned at any |
32a655c1 | 315 | /// time. You should not trust a `false` value for program correctness |
85aaf69f | 316 | /// without additional synchronization. |
32a655c1 SL |
317 | /// |
318 | /// # Examples | |
319 | /// | |
320 | /// ``` | |
321 | /// use std::sync::{Arc, Mutex}; | |
322 | /// use std::thread; | |
323 | /// | |
324 | /// let mutex = Arc::new(Mutex::new(0)); | |
1b1a35ee | 325 | /// let c_mutex = Arc::clone(&mutex); |
32a655c1 SL |
326 | /// |
327 | /// let _ = thread::spawn(move || { | |
328 | /// let _lock = c_mutex.lock().unwrap(); | |
329 | /// panic!(); // the mutex gets poisoned | |
330 | /// }).join(); | |
331 | /// assert_eq!(mutex.is_poisoned(), true); | |
332 | /// ``` | |
85aaf69f | 333 | #[inline] |
62682a34 | 334 | #[stable(feature = "sync_poison", since = "1.2.0")] |
85aaf69f | 335 | pub fn is_poisoned(&self) -> bool { |
5bcae85e | 336 | self.poison.get() |
85aaf69f | 337 | } |
b039eaaf SL |
338 | |
339 | /// Consumes this mutex, returning the underlying data. | |
340 | /// | |
7453a54e | 341 | /// # Errors |
b039eaaf SL |
342 | /// |
343 | /// If another user of this mutex panicked while holding the mutex, then | |
344 | /// this call will return an error instead. | |
32a655c1 SL |
345 | /// |
346 | /// # Examples | |
347 | /// | |
348 | /// ``` | |
349 | /// use std::sync::Mutex; | |
350 | /// | |
351 | /// let mutex = Mutex::new(0); | |
352 | /// assert_eq!(mutex.into_inner().unwrap(), 0); | |
353 | /// ``` | |
92a42be0 | 354 | #[stable(feature = "mutex_into_inner", since = "1.6.0")] |
dfeec247 XL |
355 | pub fn into_inner(self) -> LockResult<T> |
356 | where | |
357 | T: Sized, | |
358 | { | |
b039eaaf | 359 | // We know statically that there are no outstanding references to |
cc61c64b | 360 | // `self` so there's no need to lock the inner mutex. |
b039eaaf SL |
361 | // |
362 | // To get the inner value, we'd like to call `data.into_inner()`, | |
363 | // but because `Mutex` impl-s `Drop`, we can't move out of it, so | |
364 | // we'll have to destructure it manually instead. | |
365 | unsafe { | |
5bcae85e SL |
366 | // Like `let Mutex { inner, poison, data } = self`. |
367 | let (inner, poison, data) = { | |
368 | let Mutex { ref inner, ref poison, ref data } = self; | |
369 | (ptr::read(inner), ptr::read(poison), ptr::read(data)) | |
b039eaaf SL |
370 | }; |
371 | mem::forget(self); | |
5bcae85e | 372 | drop(inner); |
b039eaaf | 373 | |
5bcae85e | 374 | poison::map_result(poison.borrow(), |_| data.into_inner()) |
b039eaaf SL |
375 | } |
376 | } | |
377 | ||
378 | /// Returns a mutable reference to the underlying data. | |
379 | /// | |
380 | /// Since this call borrows the `Mutex` mutably, no actual locking needs to | |
9fa01778 | 381 | /// take place -- the mutable borrow statically guarantees no locks exist. |
b039eaaf | 382 | /// |
7453a54e | 383 | /// # Errors |
b039eaaf SL |
384 | /// |
385 | /// If another user of this mutex panicked while holding the mutex, then | |
386 | /// this call will return an error instead. | |
32a655c1 SL |
387 | /// |
388 | /// # Examples | |
389 | /// | |
390 | /// ``` | |
391 | /// use std::sync::Mutex; | |
392 | /// | |
393 | /// let mut mutex = Mutex::new(0); | |
394 | /// *mutex.get_mut().unwrap() = 10; | |
395 | /// assert_eq!(*mutex.lock().unwrap(), 10); | |
396 | /// ``` | |
92a42be0 | 397 | #[stable(feature = "mutex_get_mut", since = "1.6.0")] |
b039eaaf | 398 | pub fn get_mut(&mut self) -> LockResult<&mut T> { |
1b1a35ee | 399 | let data = self.data.get_mut(); |
dfeec247 | 400 | poison::map_result(self.poison.borrow(), |_| data) |
b039eaaf | 401 | } |
1a4d82fc JJ |
402 | } |
403 | ||
2c00a5a8 | 404 | #[stable(feature = "mutex_from", since = "1.24.0")] |
ff7c6d11 XL |
405 | impl<T> From<T> for Mutex<T> { |
406 | /// Creates a new mutex in an unlocked state ready for use. | |
407 | /// This is equivalent to [`Mutex::new`]. | |
ff7c6d11 XL |
408 | fn from(t: T) -> Self { |
409 | Mutex::new(t) | |
410 | } | |
411 | } | |
412 | ||
7cac9316 | 413 | #[stable(feature = "mutex_default", since = "1.10.0")] |
a7813a04 | 414 | impl<T: ?Sized + Default> Default for Mutex<T> { |
9e0c209e | 415 | /// Creates a `Mutex<T>`, with the `Default` value for T. |
a7813a04 XL |
416 | fn default() -> Mutex<T> { |
417 | Mutex::new(Default::default()) | |
418 | } | |
419 | } | |
420 | ||
c34b1796 | 421 | #[stable(feature = "rust1", since = "1.0.0")] |
7453a54e | 422 | impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> { |
532ac7d7 | 423 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
c34b1796 | 424 | match self.try_lock() { |
abe05a73 | 425 | Ok(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(), |
c34b1796 | 426 | Err(TryLockError::Poisoned(err)) => { |
abe05a73 | 427 | f.debug_struct("Mutex").field("data", &&**err.get_ref()).finish() |
dfeec247 | 428 | } |
abe05a73 XL |
429 | Err(TryLockError::WouldBlock) => { |
430 | struct LockedPlaceholder; | |
431 | impl fmt::Debug for LockedPlaceholder { | |
532ac7d7 XL |
432 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
433 | f.write_str("<locked>") | |
434 | } | |
abe05a73 XL |
435 | } |
436 | ||
437 | f.debug_struct("Mutex").field("data", &LockedPlaceholder).finish() | |
438 | } | |
c34b1796 AL |
439 | } |
440 | } | |
441 | } | |
442 | ||
d9579d0f | 443 | impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { |
5bcae85e | 444 | unsafe fn new(lock: &'mutex Mutex<T>) -> LockResult<MutexGuard<'mutex, T>> { |
74b04a01 | 445 | poison::map_result(lock.poison.borrow(), |guard| MutexGuard { lock, poison: guard }) |
1a4d82fc JJ |
446 | } |
447 | } | |
448 | ||
85aaf69f | 449 | #[stable(feature = "rust1", since = "1.0.0")] |
9fa01778 | 450 | impl<T: ?Sized> Deref for MutexGuard<'_, T> { |
1a4d82fc JJ |
451 | type Target = T; |
452 | ||
5bcae85e | 453 | fn deref(&self) -> &T { |
60c5eb7d | 454 | unsafe { &*self.lock.data.get() } |
5bcae85e | 455 | } |
1a4d82fc | 456 | } |
e9174d1e | 457 | |
85aaf69f | 458 | #[stable(feature = "rust1", since = "1.0.0")] |
9fa01778 | 459 | impl<T: ?Sized> DerefMut for MutexGuard<'_, T> { |
5bcae85e | 460 | fn deref_mut(&mut self) -> &mut T { |
60c5eb7d | 461 | unsafe { &mut *self.lock.data.get() } |
5bcae85e | 462 | } |
1a4d82fc JJ |
463 | } |
464 | ||
85aaf69f | 465 | #[stable(feature = "rust1", since = "1.0.0")] |
9fa01778 | 466 | impl<T: ?Sized> Drop for MutexGuard<'_, T> { |
1a4d82fc JJ |
467 | #[inline] |
468 | fn drop(&mut self) { | |
469 | unsafe { | |
60c5eb7d XL |
470 | self.lock.poison.done(&self.poison); |
471 | self.lock.inner.raw_unlock(); | |
1a4d82fc JJ |
472 | } |
473 | } | |
474 | } | |
475 | ||
8bb4bdeb | 476 | #[stable(feature = "std_debug", since = "1.16.0")] |
9fa01778 | 477 | impl<T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'_, T> { |
532ac7d7 | 478 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
9fa01778 | 479 | fmt::Debug::fmt(&**self, f) |
32a655c1 SL |
480 | } |
481 | } | |
482 | ||
041b39d2 | 483 | #[stable(feature = "std_guard_impls", since = "1.20.0")] |
9fa01778 | 484 | impl<T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'_, T> { |
532ac7d7 | 485 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
041b39d2 XL |
486 | (**self).fmt(f) |
487 | } | |
488 | } | |
489 | ||
1b1a35ee | 490 | pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::MovableMutex { |
60c5eb7d | 491 | &guard.lock.inner |
1a4d82fc JJ |
492 | } |
493 | ||
d9579d0f | 494 | pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { |
60c5eb7d | 495 | &guard.lock.poison |
1a4d82fc | 496 | } |