// Copyright 2018 The ChromiumOS Authors1// Use of this source code is governed by a BSD-style license that can be2// found in the LICENSE file.34//! Mutex type whose methods panic rather than returning error in case of5//! poison.6//!7//! The Mutex type in this module wraps the standard library Mutex and mirrors8//! the same methods, except that they panic where the standard library would9//! return a PoisonError. This API codifies our error handling strategy around10//! poisoned mutexes in crosvm.11//!12//! - Crosvm releases are built with panic=abort so poisoning never occurs. A panic while a mutex is13//! held (or ever) takes down the entire process. Thus we would like for code not to have to14//! consider the possibility of poison.15//!16//! - We could ask developers to always write `.lock().unwrap()` on a standard library mutex.17//! However, we would like to stigmatize the use of unwrap. It is confusing to permit unwrap but18//! only on mutex lock results. During code review it may not always be obvious whether a19//! particular unwrap is unwrapping a mutex lock result or a different error that should be20//! handled in a more principled way.21//!22//! Developers should feel free to use sync::Mutex anywhere in crosvm that they23//! would otherwise be using std::sync::Mutex.2425use std::fmt;26use std::fmt::Debug;27use std::fmt::Display;28use std::sync::Mutex as StdMutex;29use std::sync::MutexGuard;30use std::sync::TryLockError;3132/// A mutual exclusion primitive useful for protecting shared data.33#[derive(Default)]34pub struct Mutex<T: ?Sized> {35std: StdMutex<T>,36}3738impl<T> Mutex<T> {39/// Creates a new mutex in an unlocked state ready for use.40pub const fn new(value: T) -> Mutex<T> {41Mutex {42std: StdMutex::new(value),43}44}4546/// Consumes this mutex, returning the underlying data.47pub fn into_inner(self) -> T {48match self.std.into_inner() {49Ok(value) => value,50Err(_) => panic!("mutex is poisoned"),51}52}53}5455impl<T: ?Sized> Mutex<T> {56/// Acquires a mutex, blocking the current thread until it is able to do so.57///58/// This function will block the local thread until it is available to59/// acquire the mutex. Upon returning, the thread is the only thread with60/// the lock held. An RAII guard is returned to allow scoped unlock of the61/// lock. When the guard goes out of scope, the mutex will be unlocked.62pub fn lock(&self) -> MutexGuard<T> {63match self.std.lock() {64Ok(guard) => guard,65Err(_) => panic!("mutex is poisoned"),66}67}6869/// Attempts to acquire this lock.70///71/// If the lock could not be acquired at this time, then Err is returned.72/// Otherwise, an RAII guard is returned. The lock will be unlocked when the73/// guard is dropped.74///75/// This function does not block.76pub fn try_lock(&self) -> Result<MutexGuard<T>, WouldBlock> {77match self.std.try_lock() {78Ok(guard) => Ok(guard),79Err(TryLockError::Poisoned(_)) => panic!("mutex is poisoned"),80Err(TryLockError::WouldBlock) => Err(WouldBlock),81}82}8384/// Returns a mutable reference to the underlying data.85///86/// Since this call borrows the Mutex mutably, no actual locking needs to87/// take place -- the mutable borrow statically guarantees no locks exist.88pub fn get_mut(&mut self) -> &mut T {89match self.std.get_mut() {90Ok(value) => value,91Err(_) => panic!("mutex is poisoned"),92}93}94}9596impl<T> From<T> for Mutex<T> {97fn from(value: T) -> Self {98Mutex {99std: StdMutex::from(value),100}101}102}103104impl<T: ?Sized + Debug> Debug for Mutex<T> {105fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {106Debug::fmt(&self.std, formatter)107}108}109110/// The lock could not be acquired at this time because the operation would111/// otherwise block.112///113/// Error returned by Mutex::try_lock.114#[derive(Debug)]115pub struct WouldBlock;116117impl Display for WouldBlock {118fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {119Display::fmt(&TryLockError::WouldBlock::<()>, formatter)120}121}122123impl std::error::Error for WouldBlock {}124125126