]>
Commit | Line | Data |
---|---|---|
532ac7d7 XL |
1 | use crate::cell::UnsafeCell; |
2 | use crate::fmt; | |
3 | use crate::mem; | |
4 | use crate::ops::{Deref, DerefMut}; | |
5 | use crate::ptr; | |
6 | use crate::sys_common::mutex as sys; | |
dfeec247 | 7 | use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult}; |
1a4d82fc JJ |
8 | |
9 | /// A mutual exclusion primitive useful for protecting shared data | |
10 | /// | |
11 | /// This mutex will block threads waiting for the lock to become available. The | |
ea8adc8c | 12 | /// mutex can also be statically initialized or created via a [`new`] |
1a4d82fc JJ |
13 | /// constructor. Each mutex has a type parameter which represents the data that |
14 | /// it is protecting. The data can only be accessed through the RAII guards | |
ea8adc8c | 15 | /// returned from [`lock`] and [`try_lock`], which guarantees that the data is only |
1a4d82fc JJ |
16 | /// ever accessed when the mutex is locked. |
17 | /// | |
18 | /// # Poisoning | |
19 | /// | |
20 | /// The mutexes in this module implement a strategy called "poisoning" where a | |
21 | /// mutex is considered poisoned whenever a thread panics while holding the | |
cc61c64b | 22 | /// mutex. Once a mutex is poisoned, all other threads are unable to access the |
1a4d82fc JJ |
23 | /// data by default as it is likely tainted (some invariant is not being |
24 | /// upheld). | |
25 | /// | |
ea8adc8c XL |
26 | /// For a mutex, this means that the [`lock`] and [`try_lock`] methods return a |
27 | /// [`Result`] which indicates whether a mutex has been poisoned or not. Most | |
28 | /// usage of a mutex will simply [`unwrap()`] these results, propagating panics | |
1a4d82fc JJ |
29 | /// among threads to ensure that a possibly invalid invariant is not witnessed. |
30 | /// | |
31 | /// A poisoned mutex, however, does not prevent all access to the underlying | |
ea8adc8c | 32 | /// data. The [`PoisonError`] type has an [`into_inner`] method which will return |
1a4d82fc JJ |
33 | /// the guard that would have otherwise been returned on a successful lock. This |
34 | /// allows access to the data, despite the lock being poisoned. | |
35 | /// | |
ea8adc8c XL |
36 | /// [`new`]: #method.new |
37 | /// [`lock`]: #method.lock | |
38 | /// [`try_lock`]: #method.try_lock | |
39 | /// [`Result`]: ../../std/result/enum.Result.html | |
40 | /// [`unwrap()`]: ../../std/result/enum.Result.html#method.unwrap | |
41 | /// [`PoisonError`]: ../../std/sync/struct.PoisonError.html | |
42 | /// [`into_inner`]: ../../std/sync/struct.PoisonError.html#method.into_inner | |
43 | /// | |
1a4d82fc JJ |
44 | /// # Examples |
45 | /// | |
c34b1796 | 46 | /// ``` |
1a4d82fc | 47 | /// use std::sync::{Arc, Mutex}; |
85aaf69f | 48 | /// use std::thread; |
1a4d82fc JJ |
49 | /// use std::sync::mpsc::channel; |
50 | /// | |
c34b1796 | 51 | /// const N: usize = 10; |
1a4d82fc JJ |
52 | /// |
53 | /// // Spawn a few threads to increment a shared variable (non-atomically), and | |
54 | /// // let the main thread know once all increments are done. | |
55 | /// // | |
bd371182 | 56 | /// // Here we're using an Arc to share memory among threads, and the data inside |
1a4d82fc JJ |
57 | /// // the Arc is protected with a mutex. |
58 | /// let data = Arc::new(Mutex::new(0)); | |
59 | /// | |
60 | /// let (tx, rx) = channel(); | |
cc61c64b | 61 | /// for _ in 0..N { |
a1dfa0c6 | 62 | /// let (data, tx) = (Arc::clone(&data), tx.clone()); |
85aaf69f | 63 | /// thread::spawn(move || { |
92a42be0 | 64 | /// // The shared state can only be accessed once the lock is held. |
1a4d82fc JJ |
65 | /// // Our non-atomic increment is safe because we're the only thread |
66 | /// // which can access the shared state when the lock is held. | |
67 | /// // | |
68 | /// // We unwrap() the return value to assert that we are not expecting | |
bd371182 | 69 | /// // threads to ever fail while holding the lock. |
1a4d82fc JJ |
70 | /// let mut data = data.lock().unwrap(); |
71 | /// *data += 1; | |
72 | /// if *data == N { | |
73 | /// tx.send(()).unwrap(); | |
74 | /// } | |
75 | /// // the lock is unlocked here when `data` goes out of scope. | |
76 | /// }); | |
77 | /// } | |
78 | /// | |
79 | /// rx.recv().unwrap(); | |
80 | /// ``` | |
81 | /// | |
82 | /// To recover from a poisoned mutex: | |
83 | /// | |
c34b1796 | 84 | /// ``` |
1a4d82fc | 85 | /// use std::sync::{Arc, Mutex}; |
85aaf69f | 86 | /// use std::thread; |
1a4d82fc | 87 | /// |
85aaf69f | 88 | /// let lock = Arc::new(Mutex::new(0_u32)); |
1a4d82fc JJ |
89 | /// let lock2 = lock.clone(); |
90 | /// | |
85aaf69f | 91 | /// let _ = thread::spawn(move || -> () { |
1a4d82fc JJ |
92 | /// // This thread will acquire the mutex first, unwrapping the result of |
93 | /// // `lock` because the lock has not been poisoned. | |
7453a54e | 94 | /// let _guard = lock2.lock().unwrap(); |
1a4d82fc JJ |
95 | /// |
96 | /// // This panic while holding the lock (`_guard` is in scope) will poison | |
97 | /// // the mutex. | |
98 | /// panic!(); | |
99 | /// }).join(); | |
100 | /// | |
101 | /// // The lock is poisoned by this point, but the returned result can be | |
102 | /// // pattern matched on to return the underlying guard on both branches. | |
103 | /// let mut guard = match lock.lock() { | |
104 | /// Ok(guard) => guard, | |
c34b1796 | 105 | /// Err(poisoned) => poisoned.into_inner(), |
1a4d82fc JJ |
106 | /// }; |
107 | /// | |
108 | /// *guard += 1; | |
109 | /// ``` | |
f035d41b XL |
110 | /// |
111 | /// It is sometimes necessary to manually drop the mutex guard to unlock it | |
112 | /// sooner than the end of the enclosing scope. | |
113 | /// | |
114 | /// ``` | |
115 | /// use std::sync::{Arc, Mutex}; | |
116 | /// use std::thread; | |
117 | /// | |
118 | /// const N: usize = 3; | |
119 | /// | |
120 | /// let data_mutex = Arc::new(Mutex::new(vec![1, 2, 3, 4])); | |
121 | /// let res_mutex = Arc::new(Mutex::new(0)); | |
122 | /// | |
123 | /// let mut threads = Vec::with_capacity(N); | |
124 | /// (0..N).for_each(|_| { | |
125 | /// let data_mutex_clone = Arc::clone(&data_mutex); | |
126 | /// let res_mutex_clone = Arc::clone(&res_mutex); | |
127 | /// | |
128 | /// threads.push(thread::spawn(move || { | |
129 | /// let mut data = data_mutex_clone.lock().unwrap(); | |
130 | /// // This is the result of some important and long-ish work. | |
131 | /// let result = data.iter().fold(0, |acc, x| acc + x * 2); | |
132 | /// data.push(result); | |
133 | /// drop(data); | |
134 | /// *res_mutex_clone.lock().unwrap() += result; | |
135 | /// })); | |
136 | /// }); | |
137 | /// | |
138 | /// let mut data = data_mutex.lock().unwrap(); | |
139 | /// // This is the result of some important and long-ish work. | |
140 | /// let result = data.iter().fold(0, |acc, x| acc + x * 2); | |
141 | /// data.push(result); | |
142 | /// // We drop the `data` explicitly because it's not necessary anymore and the | |
143 | /// // thread still has work to do. This allow other threads to start working on | |
144 | /// // the data immediately, without waiting for the rest of the unrelated work | |
145 | /// // to be done here. | |
146 | /// // | |
147 | /// // It's even more important here than in the threads because we `.join` the | |
148 | /// // threads after that. If we had not dropped the mutex guard, a thread could | |
149 | /// // be waiting forever for it, causing a deadlock. | |
150 | /// drop(data); | |
151 | /// // Here the mutex guard is not assigned to a variable and so, even if the | |
152 | /// // scope does not end after this line, the mutex is still released: there is | |
153 | /// // no deadlock. | |
154 | /// *res_mutex.lock().unwrap() += result; | |
155 | /// | |
156 | /// threads.into_iter().for_each(|thread| { | |
157 | /// thread | |
158 | /// .join() | |
159 | /// .expect("The thread creating or execution failed !") | |
160 | /// }); | |
161 | /// | |
162 | /// assert_eq!(*res_mutex.lock().unwrap(), 800); | |
163 | /// ``` | |
85aaf69f | 164 | #[stable(feature = "rust1", since = "1.0.0")] |
f9f354fc | 165 | #[cfg_attr(not(test), rustc_diagnostic_item = "mutex_type")] |
d9579d0f | 166 | pub struct Mutex<T: ?Sized> { |
5bcae85e SL |
167 | // Note that this mutex is in a *box*, not inlined into the struct itself. |
168 | // Once a native mutex has been used once, its address can never change (it | |
169 | // can't be moved). This mutex type can be safely moved at any time, so to | |
cc61c64b | 170 | // ensure that the native mutex is used correctly we box the inner mutex to |
5bcae85e SL |
171 | // give it a constant address. |
172 | inner: Box<sys::Mutex>, | |
173 | poison: poison::Flag, | |
1a4d82fc JJ |
174 | data: UnsafeCell<T>, |
175 | } | |
176 | ||
c34b1796 AL |
177 | // these are the only places where `T: Send` matters; all other |
178 | // functionality works fine on a single thread. | |
92a42be0 | 179 | #[stable(feature = "rust1", since = "1.0.0")] |
dfeec247 | 180 | unsafe impl<T: ?Sized + Send> Send for Mutex<T> {} |
92a42be0 | 181 | #[stable(feature = "rust1", since = "1.0.0")] |
dfeec247 | 182 | unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {} |
1a4d82fc | 183 | |
1a4d82fc JJ |
184 | /// An RAII implementation of a "scoped lock" of a mutex. When this structure is |
185 | /// dropped (falls out of scope), the lock will be unlocked. | |
186 | /// | |
cc61c64b | 187 | /// The data protected by the mutex can be accessed through this guard via its |
8bb4bdeb | 188 | /// [`Deref`] and [`DerefMut`] implementations. |
476ff2be | 189 | /// |
cc61c64b | 190 | /// This structure is created by the [`lock`] and [`try_lock`] methods on |
476ff2be SL |
191 | /// [`Mutex`]. |
192 | /// | |
8bb4bdeb XL |
193 | /// [`Deref`]: ../../std/ops/trait.Deref.html |
194 | /// [`DerefMut`]: ../../std/ops/trait.DerefMut.html | |
cc61c64b XL |
195 | /// [`lock`]: struct.Mutex.html#method.lock |
196 | /// [`try_lock`]: struct.Mutex.html#method.try_lock | |
476ff2be | 197 | /// [`Mutex`]: struct.Mutex.html |
94b46f34 | 198 | #[must_use = "if unused the Mutex will immediately unlock"] |
85aaf69f | 199 | #[stable(feature = "rust1", since = "1.0.0")] |
d9579d0f | 200 | pub struct MutexGuard<'a, T: ?Sized + 'a> { |
60c5eb7d XL |
201 | lock: &'a Mutex<T>, |
202 | poison: poison::Guard, | |
1a4d82fc JJ |
203 | } |
204 | ||
92a42be0 | 205 | #[stable(feature = "rust1", since = "1.0.0")] |
dfeec247 | 206 | impl<T: ?Sized> !Send for MutexGuard<'_, T> {} |
7cac9316 | 207 | #[stable(feature = "mutexguard", since = "1.19.0")] |
dfeec247 | 208 | unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {} |
85aaf69f | 209 | |
c34b1796 | 210 | impl<T> Mutex<T> { |
1a4d82fc | 211 | /// Creates a new mutex in an unlocked state ready for use. |
32a655c1 SL |
212 | /// |
213 | /// # Examples | |
214 | /// | |
215 | /// ``` | |
216 | /// use std::sync::Mutex; | |
217 | /// | |
218 | /// let mutex = Mutex::new(0); | |
219 | /// ``` | |
85aaf69f | 220 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 221 | pub fn new(t: T) -> Mutex<T> { |
3157f602 | 222 | let mut m = Mutex { |
5bcae85e SL |
223 | inner: box sys::Mutex::new(), |
224 | poison: poison::Flag::new(), | |
1a4d82fc | 225 | data: UnsafeCell::new(t), |
3157f602 XL |
226 | }; |
227 | unsafe { | |
5bcae85e | 228 | m.inner.init(); |
1a4d82fc | 229 | } |
3157f602 | 230 | m |
1a4d82fc | 231 | } |
d9579d0f | 232 | } |
1a4d82fc | 233 | |
d9579d0f | 234 | impl<T: ?Sized> Mutex<T> { |
bd371182 | 235 | /// Acquires a mutex, blocking the current thread until it is able to do so. |
1a4d82fc | 236 | /// |
bd371182 | 237 | /// This function will block the local thread until it is available to acquire |
cc61c64b | 238 | /// the mutex. Upon returning, the thread is the only thread with the lock |
1a4d82fc JJ |
239 | /// held. An RAII guard is returned to allow scoped unlock of the lock. When |
240 | /// the guard goes out of scope, the mutex will be unlocked. | |
241 | /// | |
a7813a04 XL |
242 | /// The exact behavior on locking a mutex in the thread which already holds |
243 | /// the lock is left unspecified. However, this function will not return on | |
244 | /// the second call (it might panic or deadlock, for example). | |
245 | /// | |
7453a54e | 246 | /// # Errors |
1a4d82fc JJ |
247 | /// |
248 | /// If another user of this mutex panicked while holding the mutex, then | |
249 | /// this call will return an error once the mutex is acquired. | |
a7813a04 XL |
250 | /// |
251 | /// # Panics | |
252 | /// | |
253 | /// This function might panic when called if the lock is already held by | |
254 | /// the current thread. | |
32a655c1 SL |
255 | /// |
256 | /// # Examples | |
257 | /// | |
258 | /// ``` | |
259 | /// use std::sync::{Arc, Mutex}; | |
260 | /// use std::thread; | |
261 | /// | |
262 | /// let mutex = Arc::new(Mutex::new(0)); | |
263 | /// let c_mutex = mutex.clone(); | |
264 | /// | |
265 | /// thread::spawn(move || { | |
266 | /// *c_mutex.lock().unwrap() = 10; | |
267 | /// }).join().expect("thread::spawn failed"); | |
268 | /// assert_eq!(*mutex.lock().unwrap(), 10); | |
269 | /// ``` | |
85aaf69f | 270 | #[stable(feature = "rust1", since = "1.0.0")] |
532ac7d7 | 271 | pub fn lock(&self) -> LockResult<MutexGuard<'_, T>> { |
7453a54e | 272 | unsafe { |
94b46f34 | 273 | self.inner.raw_lock(); |
5bcae85e | 274 | MutexGuard::new(self) |
7453a54e | 275 | } |
1a4d82fc JJ |
276 | } |
277 | ||
278 | /// Attempts to acquire this lock. | |
279 | /// | |
ea8adc8c | 280 | /// If the lock could not be acquired at this time, then [`Err`] is returned. |
1a4d82fc JJ |
281 | /// Otherwise, an RAII guard is returned. The lock will be unlocked when the |
282 | /// guard is dropped. | |
283 | /// | |
284 | /// This function does not block. | |
285 | /// | |
7453a54e | 286 | /// # Errors |
1a4d82fc JJ |
287 | /// |
288 | /// If another user of this mutex panicked while holding the mutex, then | |
289 | /// this call will return failure if the mutex would otherwise be | |
290 | /// acquired. | |
32a655c1 | 291 | /// |
ea8adc8c XL |
292 | /// [`Err`]: ../../std/result/enum.Result.html#variant.Err |
293 | /// | |
32a655c1 SL |
294 | /// # Examples |
295 | /// | |
296 | /// ``` | |
297 | /// use std::sync::{Arc, Mutex}; | |
298 | /// use std::thread; | |
299 | /// | |
300 | /// let mutex = Arc::new(Mutex::new(0)); | |
301 | /// let c_mutex = mutex.clone(); | |
302 | /// | |
303 | /// thread::spawn(move || { | |
304 | /// let mut lock = c_mutex.try_lock(); | |
305 | /// if let Ok(ref mut mutex) = lock { | |
306 | /// **mutex = 10; | |
307 | /// } else { | |
308 | /// println!("try_lock failed"); | |
309 | /// } | |
310 | /// }).join().expect("thread::spawn failed"); | |
311 | /// assert_eq!(*mutex.lock().unwrap(), 10); | |
312 | /// ``` | |
85aaf69f | 313 | #[stable(feature = "rust1", since = "1.0.0")] |
532ac7d7 | 314 | pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T>> { |
7453a54e | 315 | unsafe { |
5bcae85e SL |
316 | if self.inner.try_lock() { |
317 | Ok(MutexGuard::new(self)?) | |
7453a54e SL |
318 | } else { |
319 | Err(TryLockError::WouldBlock) | |
320 | } | |
1a4d82fc JJ |
321 | } |
322 | } | |
85aaf69f | 323 | |
cc61c64b | 324 | /// Determines whether the mutex is poisoned. |
85aaf69f | 325 | /// |
cc61c64b | 326 | /// If another thread is active, the mutex can still become poisoned at any |
32a655c1 | 327 | /// time. You should not trust a `false` value for program correctness |
85aaf69f | 328 | /// without additional synchronization. |
32a655c1 SL |
329 | /// |
330 | /// # Examples | |
331 | /// | |
332 | /// ``` | |
333 | /// use std::sync::{Arc, Mutex}; | |
334 | /// use std::thread; | |
335 | /// | |
336 | /// let mutex = Arc::new(Mutex::new(0)); | |
337 | /// let c_mutex = mutex.clone(); | |
338 | /// | |
339 | /// let _ = thread::spawn(move || { | |
340 | /// let _lock = c_mutex.lock().unwrap(); | |
341 | /// panic!(); // the mutex gets poisoned | |
342 | /// }).join(); | |
343 | /// assert_eq!(mutex.is_poisoned(), true); | |
344 | /// ``` | |
85aaf69f | 345 | #[inline] |
62682a34 | 346 | #[stable(feature = "sync_poison", since = "1.2.0")] |
85aaf69f | 347 | pub fn is_poisoned(&self) -> bool { |
5bcae85e | 348 | self.poison.get() |
85aaf69f | 349 | } |
b039eaaf SL |
350 | |
351 | /// Consumes this mutex, returning the underlying data. | |
352 | /// | |
7453a54e | 353 | /// # Errors |
b039eaaf SL |
354 | /// |
355 | /// If another user of this mutex panicked while holding the mutex, then | |
356 | /// this call will return an error instead. | |
32a655c1 SL |
357 | /// |
358 | /// # Examples | |
359 | /// | |
360 | /// ``` | |
361 | /// use std::sync::Mutex; | |
362 | /// | |
363 | /// let mutex = Mutex::new(0); | |
364 | /// assert_eq!(mutex.into_inner().unwrap(), 0); | |
365 | /// ``` | |
92a42be0 | 366 | #[stable(feature = "mutex_into_inner", since = "1.6.0")] |
dfeec247 XL |
367 | pub fn into_inner(self) -> LockResult<T> |
368 | where | |
369 | T: Sized, | |
370 | { | |
b039eaaf | 371 | // We know statically that there are no outstanding references to |
cc61c64b | 372 | // `self` so there's no need to lock the inner mutex. |
b039eaaf SL |
373 | // |
374 | // To get the inner value, we'd like to call `data.into_inner()`, | |
375 | // but because `Mutex` impl-s `Drop`, we can't move out of it, so | |
376 | // we'll have to destructure it manually instead. | |
377 | unsafe { | |
5bcae85e SL |
378 | // Like `let Mutex { inner, poison, data } = self`. |
379 | let (inner, poison, data) = { | |
380 | let Mutex { ref inner, ref poison, ref data } = self; | |
381 | (ptr::read(inner), ptr::read(poison), ptr::read(data)) | |
b039eaaf SL |
382 | }; |
383 | mem::forget(self); | |
dfeec247 | 384 | inner.destroy(); // Keep in sync with the `Drop` impl. |
5bcae85e | 385 | drop(inner); |
b039eaaf | 386 | |
5bcae85e | 387 | poison::map_result(poison.borrow(), |_| data.into_inner()) |
b039eaaf SL |
388 | } |
389 | } | |
390 | ||
391 | /// Returns a mutable reference to the underlying data. | |
392 | /// | |
393 | /// Since this call borrows the `Mutex` mutably, no actual locking needs to | |
9fa01778 | 394 | /// take place -- the mutable borrow statically guarantees no locks exist. |
b039eaaf | 395 | /// |
7453a54e | 396 | /// # Errors |
b039eaaf SL |
397 | /// |
398 | /// If another user of this mutex panicked while holding the mutex, then | |
399 | /// this call will return an error instead. | |
32a655c1 SL |
400 | /// |
401 | /// # Examples | |
402 | /// | |
403 | /// ``` | |
404 | /// use std::sync::Mutex; | |
405 | /// | |
406 | /// let mut mutex = Mutex::new(0); | |
407 | /// *mutex.get_mut().unwrap() = 10; | |
408 | /// assert_eq!(*mutex.lock().unwrap(), 10); | |
409 | /// ``` | |
92a42be0 | 410 | #[stable(feature = "mutex_get_mut", since = "1.6.0")] |
b039eaaf SL |
411 | pub fn get_mut(&mut self) -> LockResult<&mut T> { |
412 | // We know statically that there are no other references to `self`, so | |
cc61c64b | 413 | // there's no need to lock the inner mutex. |
b039eaaf | 414 | let data = unsafe { &mut *self.data.get() }; |
dfeec247 | 415 | poison::map_result(self.poison.borrow(), |_| data) |
b039eaaf | 416 | } |
1a4d82fc JJ |
417 | } |
418 | ||
85aaf69f | 419 | #[stable(feature = "rust1", since = "1.0.0")] |
32a655c1 | 420 | unsafe impl<#[may_dangle] T: ?Sized> Drop for Mutex<T> { |
1a4d82fc JJ |
421 | fn drop(&mut self) { |
422 | // This is actually safe b/c we know that there is no further usage of | |
423 | // this mutex (it's up to the user to arrange for a mutex to get | |
424 | // dropped, that's not our job) | |
b039eaaf SL |
425 | // |
426 | // IMPORTANT: This code must be kept in sync with `Mutex::into_inner`. | |
5bcae85e | 427 | unsafe { self.inner.destroy() } |
1a4d82fc JJ |
428 | } |
429 | } | |
430 | ||
2c00a5a8 | 431 | #[stable(feature = "mutex_from", since = "1.24.0")] |
ff7c6d11 XL |
432 | impl<T> From<T> for Mutex<T> { |
433 | /// Creates a new mutex in an unlocked state ready for use. | |
434 | /// This is equivalent to [`Mutex::new`]. | |
48663c56 XL |
435 | /// |
436 | /// [`Mutex::new`]: ../../std/sync/struct.Mutex.html#method.new | |
ff7c6d11 XL |
437 | fn from(t: T) -> Self { |
438 | Mutex::new(t) | |
439 | } | |
440 | } | |
441 | ||
7cac9316 | 442 | #[stable(feature = "mutex_default", since = "1.10.0")] |
a7813a04 | 443 | impl<T: ?Sized + Default> Default for Mutex<T> { |
9e0c209e | 444 | /// Creates a `Mutex<T>`, with the `Default` value for T. |
a7813a04 XL |
445 | fn default() -> Mutex<T> { |
446 | Mutex::new(Default::default()) | |
447 | } | |
448 | } | |
449 | ||
c34b1796 | 450 | #[stable(feature = "rust1", since = "1.0.0")] |
7453a54e | 451 | impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> { |
532ac7d7 | 452 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
c34b1796 | 453 | match self.try_lock() { |
abe05a73 | 454 | Ok(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(), |
c34b1796 | 455 | Err(TryLockError::Poisoned(err)) => { |
abe05a73 | 456 | f.debug_struct("Mutex").field("data", &&**err.get_ref()).finish() |
dfeec247 | 457 | } |
abe05a73 XL |
458 | Err(TryLockError::WouldBlock) => { |
459 | struct LockedPlaceholder; | |
460 | impl fmt::Debug for LockedPlaceholder { | |
532ac7d7 XL |
461 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
462 | f.write_str("<locked>") | |
463 | } | |
abe05a73 XL |
464 | } |
465 | ||
466 | f.debug_struct("Mutex").field("data", &LockedPlaceholder).finish() | |
467 | } | |
c34b1796 AL |
468 | } |
469 | } | |
470 | } | |
471 | ||
d9579d0f | 472 | impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { |
5bcae85e | 473 | unsafe fn new(lock: &'mutex Mutex<T>) -> LockResult<MutexGuard<'mutex, T>> { |
74b04a01 | 474 | poison::map_result(lock.poison.borrow(), |guard| MutexGuard { lock, poison: guard }) |
1a4d82fc JJ |
475 | } |
476 | } | |
477 | ||
85aaf69f | 478 | #[stable(feature = "rust1", since = "1.0.0")] |
9fa01778 | 479 | impl<T: ?Sized> Deref for MutexGuard<'_, T> { |
1a4d82fc JJ |
480 | type Target = T; |
481 | ||
5bcae85e | 482 | fn deref(&self) -> &T { |
60c5eb7d | 483 | unsafe { &*self.lock.data.get() } |
5bcae85e | 484 | } |
1a4d82fc | 485 | } |
e9174d1e | 486 | |
85aaf69f | 487 | #[stable(feature = "rust1", since = "1.0.0")] |
9fa01778 | 488 | impl<T: ?Sized> DerefMut for MutexGuard<'_, T> { |
5bcae85e | 489 | fn deref_mut(&mut self) -> &mut T { |
60c5eb7d | 490 | unsafe { &mut *self.lock.data.get() } |
5bcae85e | 491 | } |
1a4d82fc JJ |
492 | } |
493 | ||
85aaf69f | 494 | #[stable(feature = "rust1", since = "1.0.0")] |
9fa01778 | 495 | impl<T: ?Sized> Drop for MutexGuard<'_, T> { |
1a4d82fc JJ |
496 | #[inline] |
497 | fn drop(&mut self) { | |
498 | unsafe { | |
60c5eb7d XL |
499 | self.lock.poison.done(&self.poison); |
500 | self.lock.inner.raw_unlock(); | |
1a4d82fc JJ |
501 | } |
502 | } | |
503 | } | |
504 | ||
8bb4bdeb | 505 | #[stable(feature = "std_debug", since = "1.16.0")] |
9fa01778 | 506 | impl<T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'_, T> { |
532ac7d7 | 507 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
9fa01778 | 508 | fmt::Debug::fmt(&**self, f) |
32a655c1 SL |
509 | } |
510 | } | |
511 | ||
041b39d2 | 512 | #[stable(feature = "std_guard_impls", since = "1.20.0")] |
9fa01778 | 513 | impl<T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'_, T> { |
532ac7d7 | 514 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
041b39d2 XL |
515 | (**self).fmt(f) |
516 | } | |
517 | } | |
518 | ||
d9579d0f | 519 | pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { |
60c5eb7d | 520 | &guard.lock.inner |
1a4d82fc JJ |
521 | } |
522 | ||
d9579d0f | 523 | pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { |
60c5eb7d | 524 | &guard.lock.poison |
1a4d82fc JJ |
525 | } |
526 | ||
c30ab7b3 | 527 | #[cfg(all(test, not(target_os = "emscripten")))] |
d9579d0f | 528 | mod tests { |
532ac7d7 | 529 | use crate::sync::atomic::{AtomicUsize, Ordering}; |
dfeec247 XL |
530 | use crate::sync::mpsc::channel; |
531 | use crate::sync::{Arc, Condvar, Mutex}; | |
532ac7d7 | 532 | use crate::thread; |
1a4d82fc | 533 | |
e9174d1e | 534 | struct Packet<T>(Arc<(Mutex<T>, Condvar)>); |
1a4d82fc | 535 | |
b039eaaf SL |
536 | #[derive(Eq, PartialEq, Debug)] |
537 | struct NonCopy(i32); | |
538 | ||
1a4d82fc JJ |
539 | #[test] |
540 | fn smoke() { | |
541 | let m = Mutex::new(()); | |
542 | drop(m.lock().unwrap()); | |
543 | drop(m.lock().unwrap()); | |
544 | } | |
545 | ||
1a4d82fc JJ |
546 | #[test] |
547 | fn lots_and_lots() { | |
c34b1796 AL |
548 | const J: u32 = 1000; |
549 | const K: u32 = 3; | |
1a4d82fc | 550 | |
5bcae85e SL |
551 | let m = Arc::new(Mutex::new(0)); |
552 | ||
553 | fn inc(m: &Mutex<u32>) { | |
85aaf69f | 554 | for _ in 0..J { |
5bcae85e | 555 | *m.lock().unwrap() += 1; |
1a4d82fc JJ |
556 | } |
557 | } | |
558 | ||
559 | let (tx, rx) = channel(); | |
85aaf69f | 560 | for _ in 0..K { |
1a4d82fc | 561 | let tx2 = tx.clone(); |
5bcae85e | 562 | let m2 = m.clone(); |
dfeec247 XL |
563 | thread::spawn(move || { |
564 | inc(&m2); | |
565 | tx2.send(()).unwrap(); | |
566 | }); | |
1a4d82fc | 567 | let tx2 = tx.clone(); |
5bcae85e | 568 | let m2 = m.clone(); |
dfeec247 XL |
569 | thread::spawn(move || { |
570 | inc(&m2); | |
571 | tx2.send(()).unwrap(); | |
572 | }); | |
1a4d82fc JJ |
573 | } |
574 | ||
575 | drop(tx); | |
85aaf69f | 576 | for _ in 0..2 * K { |
1a4d82fc JJ |
577 | rx.recv().unwrap(); |
578 | } | |
5bcae85e | 579 | assert_eq!(*m.lock().unwrap(), J * K * 2); |
1a4d82fc JJ |
580 | } |
581 | ||
582 | #[test] | |
583 | fn try_lock() { | |
584 | let m = Mutex::new(()); | |
585 | *m.try_lock().unwrap() = (); | |
586 | } | |
587 | ||
b039eaaf SL |
588 | #[test] |
589 | fn test_into_inner() { | |
590 | let m = Mutex::new(NonCopy(10)); | |
591 | assert_eq!(m.into_inner().unwrap(), NonCopy(10)); | |
592 | } | |
593 | ||
594 | #[test] | |
595 | fn test_into_inner_drop() { | |
596 | struct Foo(Arc<AtomicUsize>); | |
597 | impl Drop for Foo { | |
598 | fn drop(&mut self) { | |
599 | self.0.fetch_add(1, Ordering::SeqCst); | |
600 | } | |
601 | } | |
602 | let num_drops = Arc::new(AtomicUsize::new(0)); | |
603 | let m = Mutex::new(Foo(num_drops.clone())); | |
604 | assert_eq!(num_drops.load(Ordering::SeqCst), 0); | |
605 | { | |
606 | let _inner = m.into_inner().unwrap(); | |
607 | assert_eq!(num_drops.load(Ordering::SeqCst), 0); | |
608 | } | |
609 | assert_eq!(num_drops.load(Ordering::SeqCst), 1); | |
610 | } | |
611 | ||
612 | #[test] | |
613 | fn test_into_inner_poison() { | |
614 | let m = Arc::new(Mutex::new(NonCopy(10))); | |
615 | let m2 = m.clone(); | |
616 | let _ = thread::spawn(move || { | |
617 | let _lock = m2.lock().unwrap(); | |
618 | panic!("test panic in inner thread to poison mutex"); | |
dfeec247 XL |
619 | }) |
620 | .join(); | |
b039eaaf SL |
621 | |
622 | assert!(m.is_poisoned()); | |
623 | match Arc::try_unwrap(m).unwrap().into_inner() { | |
624 | Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), | |
625 | Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x), | |
626 | } | |
627 | } | |
628 | ||
629 | #[test] | |
630 | fn test_get_mut() { | |
631 | let mut m = Mutex::new(NonCopy(10)); | |
632 | *m.get_mut().unwrap() = NonCopy(20); | |
633 | assert_eq!(m.into_inner().unwrap(), NonCopy(20)); | |
634 | } | |
635 | ||
636 | #[test] | |
637 | fn test_get_mut_poison() { | |
638 | let m = Arc::new(Mutex::new(NonCopy(10))); | |
639 | let m2 = m.clone(); | |
640 | let _ = thread::spawn(move || { | |
641 | let _lock = m2.lock().unwrap(); | |
642 | panic!("test panic in inner thread to poison mutex"); | |
dfeec247 XL |
643 | }) |
644 | .join(); | |
b039eaaf SL |
645 | |
646 | assert!(m.is_poisoned()); | |
647 | match Arc::try_unwrap(m).unwrap().get_mut() { | |
648 | Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), | |
649 | Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x), | |
650 | } | |
651 | } | |
652 | ||
1a4d82fc JJ |
653 | #[test] |
654 | fn test_mutex_arc_condvar() { | |
655 | let packet = Packet(Arc::new((Mutex::new(false), Condvar::new()))); | |
656 | let packet2 = Packet(packet.0.clone()); | |
657 | let (tx, rx) = channel(); | |
dfeec247 | 658 | let _t = thread::spawn(move || { |
1a4d82fc JJ |
659 | // wait until parent gets in |
660 | rx.recv().unwrap(); | |
661 | let &(ref lock, ref cvar) = &*packet2.0; | |
662 | let mut lock = lock.lock().unwrap(); | |
663 | *lock = true; | |
664 | cvar.notify_one(); | |
665 | }); | |
666 | ||
667 | let &(ref lock, ref cvar) = &*packet.0; | |
668 | let mut lock = lock.lock().unwrap(); | |
669 | tx.send(()).unwrap(); | |
670 | assert!(!*lock); | |
671 | while !*lock { | |
672 | lock = cvar.wait(lock).unwrap(); | |
673 | } | |
674 | } | |
675 | ||
676 | #[test] | |
677 | fn test_arc_condvar_poison() { | |
85aaf69f | 678 | let packet = Packet(Arc::new((Mutex::new(1), Condvar::new()))); |
1a4d82fc JJ |
679 | let packet2 = Packet(packet.0.clone()); |
680 | let (tx, rx) = channel(); | |
681 | ||
85aaf69f | 682 | let _t = thread::spawn(move || -> () { |
1a4d82fc JJ |
683 | rx.recv().unwrap(); |
684 | let &(ref lock, ref cvar) = &*packet2.0; | |
685 | let _g = lock.lock().unwrap(); | |
686 | cvar.notify_one(); | |
687 | // Parent should fail when it wakes up. | |
688 | panic!(); | |
689 | }); | |
690 | ||
691 | let &(ref lock, ref cvar) = &*packet.0; | |
692 | let mut lock = lock.lock().unwrap(); | |
693 | tx.send(()).unwrap(); | |
694 | while *lock == 1 { | |
695 | match cvar.wait(lock) { | |
696 | Ok(l) => { | |
697 | lock = l; | |
698 | assert_eq!(*lock, 1); | |
699 | } | |
700 | Err(..) => break, | |
701 | } | |
702 | } | |
703 | } | |
704 | ||
705 | #[test] | |
706 | fn test_mutex_arc_poison() { | |
85aaf69f SL |
707 | let arc = Arc::new(Mutex::new(1)); |
708 | assert!(!arc.is_poisoned()); | |
1a4d82fc | 709 | let arc2 = arc.clone(); |
dfeec247 | 710 | let _ = thread::spawn(move || { |
1a4d82fc JJ |
711 | let lock = arc2.lock().unwrap(); |
712 | assert_eq!(*lock, 2); | |
dfeec247 XL |
713 | }) |
714 | .join(); | |
1a4d82fc | 715 | assert!(arc.lock().is_err()); |
85aaf69f | 716 | assert!(arc.is_poisoned()); |
1a4d82fc JJ |
717 | } |
718 | ||
719 | #[test] | |
720 | fn test_mutex_arc_nested() { | |
721 | // Tests nested mutexes and access | |
722 | // to underlying data. | |
85aaf69f | 723 | let arc = Arc::new(Mutex::new(1)); |
1a4d82fc JJ |
724 | let arc2 = Arc::new(Mutex::new(arc)); |
725 | let (tx, rx) = channel(); | |
dfeec247 | 726 | let _t = thread::spawn(move || { |
1a4d82fc JJ |
727 | let lock = arc2.lock().unwrap(); |
728 | let lock2 = lock.lock().unwrap(); | |
729 | assert_eq!(*lock2, 1); | |
730 | tx.send(()).unwrap(); | |
731 | }); | |
732 | rx.recv().unwrap(); | |
733 | } | |
734 | ||
735 | #[test] | |
736 | fn test_mutex_arc_access_in_unwind() { | |
85aaf69f | 737 | let arc = Arc::new(Mutex::new(1)); |
1a4d82fc | 738 | let arc2 = arc.clone(); |
dfeec247 | 739 | let _ = thread::spawn(move || -> () { |
1a4d82fc | 740 | struct Unwinder { |
c34b1796 | 741 | i: Arc<Mutex<i32>>, |
1a4d82fc JJ |
742 | } |
743 | impl Drop for Unwinder { | |
744 | fn drop(&mut self) { | |
745 | *self.i.lock().unwrap() += 1; | |
746 | } | |
747 | } | |
748 | let _u = Unwinder { i: arc2 }; | |
749 | panic!(); | |
dfeec247 XL |
750 | }) |
751 | .join(); | |
1a4d82fc JJ |
752 | let lock = arc.lock().unwrap(); |
753 | assert_eq!(*lock, 2); | |
754 | } | |
d9579d0f | 755 | |
b039eaaf SL |
756 | #[test] |
757 | fn test_mutex_unsized() { | |
758 | let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); | |
759 | { | |
760 | let b = &mut *mutex.lock().unwrap(); | |
761 | b[0] = 4; | |
762 | b[2] = 5; | |
763 | } | |
764 | let comp: &[i32] = &[4, 2, 5]; | |
765 | assert_eq!(&*mutex.lock().unwrap(), comp); | |
766 | } | |
1a4d82fc | 767 | } |