#![allow(unsafe_code)] //! [`RawMutex`] backend using `std::sync::Mutex`. //! //! [`StdMutex`] wraps `std::sync::Mutex<()>` and implements surelock's //! [`RawMutex`] trait. Poisoned mutexes panic on //! acquisition -- consistent with the near-universal `.lock().unwrap()` //! pattern and with surelock's position that poisoning is orthogonal //! to deadlock prevention (see ADR-7). //! //! This is the default backend when the `std` feature is enabled. extern crate std; use std::sync; use super::RawMutex; /// A raw mutex backed by [`std::sync::Mutex`]. /// /// Panics if the underlying `std::sync::Mutex` is poisoned (a panic /// previously unwound through a critical section). This matches the /// `.lock().unwrap()` convention used by the vast majority of /// `std::sync::Mutex` users. pub struct StdMutex { inner: sync::Mutex<()>, } impl StdMutex { /// Create a new unlocked `StdMutex`. #[must_use] pub const fn const_new() -> Self { Self { inner: sync::Mutex::new(()), } } } impl Default for StdMutex { fn default() -> Self { Self::const_new() } } impl core::fmt::Debug for StdMutex { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("StdMutex").finish_non_exhaustive() } } unsafe impl RawMutex for StdMutex { type Guard<'a> = sync::MutexGuard<'a, ()>; fn new() -> Self { Self::const_new() } #[allow(clippy::expect_used)] // Intentional -- poisoned mutex should panic loudly fn lock(&self) -> Self::Guard<'_> { self.inner .lock() .expect("surelock: mutex poisoned (a panic occurred in a critical section)") } #[allow(clippy::panic)] // Intentional -- poisoned mutex should panic loudly fn try_lock(&self) -> Option> { match self.inner.try_lock() { Ok(guard) => Some(guard), Err(sync::TryLockError::WouldBlock) => None, Err(sync::TryLockError::Poisoned(_)) => { panic!("surelock: mutex poisoned (a panic occurred in a critical section)"); } } } } // SAFETY: std::sync::Mutex<()> is Send + Sync. unsafe impl Send for StdMutex {} unsafe impl Sync for StdMutex {}