1 // Copyright 2018 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 //! Mutex type whose methods panic rather than returning error in case of 6 //! poison. 7 //! 8 //! The Mutex type in this module wraps the standard library Mutex and mirrors 9 //! the same methods, except that they panic where the standard library would 10 //! return a PoisonError. This API codifies our error handling strategy around 11 //! poisoned mutexes in crosvm. 12 //! 13 //! - Crosvm releases are built with panic=abort so poisoning never occurs. A panic while a mutex is 14 //! held (or ever) takes down the entire process. Thus we would like for code not to have to 15 //! consider the possibility of poison. 16 //! 17 //! - We could ask developers to always write `.lock().unwrap()` on a standard library mutex. 18 //! However, we would like to stigmatize the use of unwrap. It is confusing to permit unwrap but 19 //! only on mutex lock results. During code review it may not always be obvious whether a 20 //! particular unwrap is unwrapping a mutex lock result or a different error that should be 21 //! handled in a more principled way. 22 //! 23 //! Developers should feel free to use sync::Mutex anywhere in crosvm that they 24 //! would otherwise be using std::sync::Mutex. 25 26 use std::fmt; 27 use std::fmt::Debug; 28 use std::fmt::Display; 29 use std::sync::Mutex as StdMutex; 30 use std::sync::MutexGuard; 31 use std::sync::TryLockError; 32 33 /// A mutual exclusion primitive useful for protecting shared data. 34 #[derive(Default)] 35 pub struct Mutex<T: ?Sized> { 36 std: StdMutex<T>, 37 } 38 39 impl<T> Mutex<T> { 40 /// Creates a new mutex in an unlocked state ready for use. new(value: T) -> Mutex<T>41 pub const fn new(value: T) -> Mutex<T> { 42 Mutex { 43 std: StdMutex::new(value), 44 } 45 } 46 47 /// Consumes this mutex, returning the underlying data. into_inner(self) -> T48 pub fn into_inner(self) -> T { 49 match self.std.into_inner() { 50 Ok(value) => value, 51 Err(_) => panic!("mutex is poisoned"), 52 } 53 } 54 } 55 56 impl<T: ?Sized> Mutex<T> { 57 /// Acquires a mutex, blocking the current thread until it is able to do so. 58 /// 59 /// This function will block the local thread until it is available to 60 /// acquire the mutex. Upon returning, the thread is the only thread with 61 /// the lock held. An RAII guard is returned to allow scoped unlock of the 62 /// lock. When the guard goes out of scope, the mutex will be unlocked. lock(&self) -> MutexGuard<T>63 pub fn lock(&self) -> MutexGuard<T> { 64 match self.std.lock() { 65 Ok(guard) => guard, 66 Err(_) => panic!("mutex is poisoned"), 67 } 68 } 69 70 /// Attempts to acquire this lock. 71 /// 72 /// If the lock could not be acquired at this time, then Err is returned. 73 /// Otherwise, an RAII guard is returned. The lock will be unlocked when the 74 /// guard is dropped. 75 /// 76 /// This function does not block. try_lock(&self) -> Result<MutexGuard<T>, WouldBlock>77 pub fn try_lock(&self) -> Result<MutexGuard<T>, WouldBlock> { 78 match self.std.try_lock() { 79 Ok(guard) => Ok(guard), 80 Err(TryLockError::Poisoned(_)) => panic!("mutex is poisoned"), 81 Err(TryLockError::WouldBlock) => Err(WouldBlock), 82 } 83 } 84 85 /// Returns a mutable reference to the underlying data. 86 /// 87 /// Since this call borrows the Mutex mutably, no actual locking needs to 88 /// take place -- the mutable borrow statically guarantees no locks exist. get_mut(&mut self) -> &mut T89 pub fn get_mut(&mut self) -> &mut T { 90 match self.std.get_mut() { 91 Ok(value) => value, 92 Err(_) => panic!("mutex is poisoned"), 93 } 94 } 95 } 96 97 impl<T> From<T> for Mutex<T> { from(value: T) -> Self98 fn from(value: T) -> Self { 99 Mutex { 100 std: StdMutex::from(value), 101 } 102 } 103 } 104 105 impl<T: ?Sized + Debug> Debug for Mutex<T> { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result106 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 107 Debug::fmt(&self.std, formatter) 108 } 109 } 110 111 /// The lock could not be acquired at this time because the operation would 112 /// otherwise block. 113 /// 114 /// Error returned by Mutex::try_lock. 115 #[derive(Debug)] 116 pub struct WouldBlock; 117 118 impl Display for WouldBlock { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result119 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 120 Display::fmt(&TryLockError::WouldBlock::<()>, formatter) 121 } 122 } 123 124 impl std::error::Error for WouldBlock {} 125