diff --git a/benches/mutex.rs b/benches/mutex.rs index 0c75198..3fe8b83 100644 --- a/benches/mutex.rs +++ b/benches/mutex.rs @@ -7,7 +7,7 @@ use criterion::BenchmarkId; use criterion::Criterion; use criterion::Throughput; use rand::prelude::*; -use tracing_mutex::stdsync::TracingMutex; +use tracing_mutex::stdsync::tracing::Mutex as TracingMutex; const SAMPLE_SIZES: [usize; 5] = [10, 30, 100, 300, 1000]; diff --git a/src/parkinglot.rs b/src/parkinglot.rs index fff2cb4..6f12a0a 100644 --- a/src/parkinglot.rs +++ b/src/parkinglot.rs @@ -1,19 +1,20 @@ //! Wrapper types and type aliases for tracing [`parking_lot`] mutexes. //! //! This module provides type aliases that use the [`lockapi`][crate::lockapi] module to provide -//! tracing variants of the `parking_lot` primitives. Each of the `TracingX` type aliases wraps an -//! `X` in the `parkint_lot` api with dependency tracking, and a `DebugX` will refer to a `TracingX` -//! when `debug_assertions` are enabled and to `X` when they're not. This can be used to aid -//! debugging in development while enjoying maximum performance in production. +//! tracing variants of the `parking_lot` primitives. The [`tracing`] module contains type aliases +//! that use dependency tracking, while the main `parking_lot` primitives are reexported as [`raw`]. +//! +//! This main module imports from [`tracing`] when `debug_assertions` are enabled, and from [`raw`] +//! when they're not. Note that primitives for which no tracing wrapper exists are not imported into +//! the main module. //! //! # Usage //! //! ``` //! # use std::sync::Arc; //! # use std::thread; -//! # use lock_api::Mutex; -//! # use tracing_mutex::parkinglot::TracingMutex; -//! let mutex = Arc::new(TracingMutex::new(0)); +//! use tracing_mutex::parkinglot::Mutex; +//! let mutex = Arc::new(Mutex::new(0)); //! //! let handles: Vec<_> = (0..10).map(|_| { //! let mutex = Arc::clone(&mutex); @@ -37,191 +38,130 @@ //! In addition, the mutex guards returned by the tracing wrappers are `!Send`, regardless of //! whether `parking_lot` is configured to have `Send` mutex guards. This is a limitation of the //! current bookkeeping system. -use parking_lot::Once; -use parking_lot::OnceState; -use crate::lockapi::TracingWrapper; -use crate::LazyMutexId; +pub use parking_lot as raw; -macro_rules! debug_variant { - ($debug_name:ident, $tracing_name:ident, $normal_name:ty) => { - type $tracing_name = TracingWrapper<$normal_name>; +#[cfg(debug_assertions)] +pub use tracing::{ + FairMutex, FairMutexGuard, MappedFairMutexGuard, MappedMutexGuard, MappedReentrantMutexGuard, + MappedRwLockReadGuard, MappedRwLockWriteGuard, Mutex, MutexGuard, Once, OnceState, + ReentrantMutex, ReentrantMutexGuard, RwLock, RwLockReadGuard, RwLockUpgradableReadGuard, + RwLockWriteGuard, +}; - #[cfg(debug_assertions)] - type $debug_name = TracingWrapper<$normal_name>; - #[cfg(not(debug_assertions))] - type $debug_name = $normal_name; - }; -} +#[cfg(not(debug_assertions))] +pub use parking_lot::{ + FairMutex, FairMutexGuard, MappedFairMutexGuard, MappedMutexGuard, MappedReentrantMutexGuard, + MappedRwLockReadGuard, MappedRwLockWriteGuard, Mutex, MutexGuard, Once, OnceState, + ReentrantMutex, ReentrantMutexGuard, RwLock, RwLockReadGuard, RwLockUpgradableReadGuard, + RwLockWriteGuard, +}; -debug_variant!( - DebugRawFairMutex, - TracingRawFairMutex, - parking_lot::RawFairMutex -); -debug_variant!(DebugRawMutex, TracingRawMutex, parking_lot::RawMutex); -debug_variant!(DebugRawRwLock, TracingRawRwLock, parking_lot::RawRwLock); +/// Dependency tracing wrappers for [`parking_lot`]. +pub mod tracing { + pub use parking_lot::OnceState; -/// Dependency tracking fair mutex. See: [`parking_lot::FairMutex`]. -pub type TracingFairMutex = lock_api::Mutex; -/// Mutex guard for [`TracingFairMutex`]. -pub type TracingFairMutexGuard<'a, T> = lock_api::MutexGuard<'a, TracingRawFairMutex, T>; -/// RAII guard for `TracingFairMutexGuard::map`. -pub type TracingMappedFairMutexGuard<'a, T> = - lock_api::MappedMutexGuard<'a, TracingRawFairMutex, T>; -/// Debug-only dependency tracking fair mutex. -/// -/// If debug assertions are enabled this resolves to [`TracingFairMutex`] and to -/// [`parking_lot::FairMutex`] otherwise. -pub type DebugFairMutex = lock_api::Mutex; -/// Mutex guard for [`DebugFairMutex`]. -pub type DebugFairMutexGuard<'a, T> = lock_api::MutexGuard<'a, DebugRawFairMutex, T>; -/// RAII guard for `DebugFairMutexGuard::map`. -pub type DebugMappedFairMutexGuard<'a, T> = lock_api::MappedMutexGuard<'a, DebugRawFairMutex, T>; + use crate::lockapi::TracingWrapper; + use crate::LazyMutexId; -/// Dependency tracking mutex. See: [`parking_lot::Mutex`]. -pub type TracingMutex = lock_api::Mutex; -/// Mutex guard for [`TracingMutex`]. -pub type TracingMutexGuard<'a, T> = lock_api::MutexGuard<'a, TracingRawMutex, T>; -/// RAII guard for `TracingMutexGuard::map`. -pub type TracingMappedMutexGuard<'a, T> = lock_api::MappedMutexGuard<'a, TracingRawMutex, T>; -/// Debug-only dependency tracking mutex. -/// -/// If debug assertions are enabled this resolves to [`TracingMutex`] and to [`parking_lot::Mutex`] -/// otherwise. -pub type DebugMutex = lock_api::Mutex; -/// Mutex guard for [`DebugMutex`]. -pub type DebugMutexGuard<'a, T> = lock_api::MutexGuard<'a, DebugRawMutex, T>; -/// RAII guard for `TracingMutexGuard::map`. -pub type DebugMappedMutexGuard<'a, T> = lock_api::MappedMutexGuard<'a, DebugRawMutex, T>; + type RawFairMutex = TracingWrapper; + type RawMutex = TracingWrapper; + type RawRwLock = TracingWrapper; -/// Dependency tracking reentrant mutex. See: [`parking_lot::ReentrantMutex`]. -/// -/// **Note:** due to the way dependencies are tracked, this mutex can only be acquired directly -/// after itself. Acquiring any other mutex in between introduces a dependency cycle, and will -/// therefore be rejected. -pub type TracingReentrantMutex = - lock_api::ReentrantMutex, parking_lot::RawThreadId, T>; -/// Mutex guard for [`TracingReentrantMutex`]. -pub type TracingReentrantMutexGuard<'a, T> = lock_api::ReentrantMutexGuard< - 'a, - TracingWrapper, - parking_lot::RawThreadId, - T, ->; -/// RAII guard for `TracingReentrantMutexGuard::map`. -pub type TracingMappedReentrantMutexGuard<'a, T> = - lock_api::MappedReentrantMutexGuard<'a, TracingRawMutex, parking_lot::RawThreadId, T>; + /// Dependency tracking fair mutex. See: [`parking_lot::FairMutex`]. + pub type FairMutex = lock_api::Mutex; + /// Mutex guard for [`FairMutex`]. + pub type FairMutexGuard<'a, T> = lock_api::MutexGuard<'a, RawFairMutex, T>; + /// RAII guard for [`FairMutexGuard::map`]. + pub type MappedFairMutexGuard<'a, T> = lock_api::MappedMutexGuard<'a, RawFairMutex, T>; -/// Debug-only dependency tracking reentrant mutex. -/// -/// If debug assertions are enabled this resolves to [`TracingReentrantMutex`] and to -/// [`parking_lot::ReentrantMutex`] otherwise. -pub type DebugReentrantMutex = - lock_api::ReentrantMutex; -/// Mutex guard for [`DebugReentrantMutex`]. -pub type DebugReentrantMutexGuard<'a, T> = - lock_api::ReentrantMutexGuard<'a, DebugRawMutex, parking_lot::RawThreadId, T>; -/// RAII guard for `DebugReentrantMutexGuard::map`. -pub type DebugMappedReentrantMutexGuard<'a, T> = - lock_api::MappedReentrantMutexGuard<'a, DebugRawMutex, parking_lot::RawThreadId, T>; + /// Dependency tracking mutex. See: [`parking_lot::Mutex`]. + pub type Mutex = lock_api::Mutex; + /// Mutex guard for [`Mutex`]. + pub type MutexGuard<'a, T> = lock_api::MutexGuard<'a, RawMutex, T>; + /// RAII guard for [`MutexGuard::map`]. + pub type MappedMutexGuard<'a, T> = lock_api::MappedMutexGuard<'a, RawMutex, T>; -/// Dependency tracking RwLock. See: [`parking_lot::RwLock`]. -pub type TracingRwLock = lock_api::RwLock; -/// Read guard for [`TracingRwLock`]. -pub type TracingRwLockReadGuard<'a, T> = lock_api::RwLockReadGuard<'a, TracingRawRwLock, T>; -/// Upgradable Read guard for [`TracingRwLock`]. -pub type TracingRwLockUpgradableReadGuard<'a, T> = - lock_api::RwLockUpgradableReadGuard<'a, TracingRawRwLock, T>; -/// Write guard for [`TracingRwLock`]. -pub type TracingRwLockWriteGuard<'a, T> = lock_api::RwLockWriteGuard<'a, TracingRawRwLock, T>; -/// RAII guard for `TracingRwLockReadGuard::map`. -pub type TracingMappedRwLockReadGuard<'a, T> = - lock_api::MappedRwLockReadGuard<'a, TracingRawRwLock, T>; -/// RAII guard for `TracingRwLockWriteGuard::map`. -pub type TracingMappedRwLockWriteGuard<'a, T> = - lock_api::MappedRwLockWriteGuard<'a, TracingRawRwLock, T>; + /// Dependency tracking reentrant mutex. See: [`parking_lot::ReentrantMutex`]. + /// + /// **Note:** due to the way dependencies are tracked, this mutex can only be acquired directly + /// after itself. Acquiring any other mutex in between introduces a dependency cycle, and will + /// therefore be rejected. + pub type ReentrantMutex = lock_api::ReentrantMutex; + /// Mutex guard for [`ReentrantMutex`]. + pub type ReentrantMutexGuard<'a, T> = + lock_api::ReentrantMutexGuard<'a, RawMutex, parking_lot::RawThreadId, T>; + /// RAII guard for `ReentrantMutexGuard::map`. + pub type MappedReentrantMutexGuard<'a, T> = + lock_api::MappedReentrantMutexGuard<'a, RawMutex, parking_lot::RawThreadId, T>; -/// Debug-only dependency tracking RwLock. -/// -/// If debug assertions are enabled this resolved to [`TracingRwLock`] and to -/// [`parking_lot::RwLock`] otherwise. -pub type DebugRwLock = lock_api::RwLock; -/// Read guard for [`TracingRwLock`]. -pub type DebugRwLockReadGuard<'a, T> = lock_api::RwLockReadGuard<'a, DebugRawRwLock, T>; -/// Upgradable Read guard for [`TracingRwLock`]. -pub type DebugRwLockUpgradableReadGuard<'a, T> = - lock_api::RwLockUpgradableReadGuard<'a, DebugRawRwLock, T>; -/// Write guard for [`TracingRwLock`]. -pub type DebugRwLockWriteGuard<'a, T> = lock_api::RwLockWriteGuard<'a, DebugRawRwLock, T>; -/// RAII guard for `DebugRwLockReadGuard::map`. -pub type DebugMappedRwLockReadGuard<'a, T> = lock_api::MappedRwLockReadGuard<'a, DebugRawRwLock, T>; -/// RAII guard for `DebugRwLockWriteGuard::map`. -pub type DebugMappedRwLockWriteGuard<'a, T> = - lock_api::MappedRwLockWriteGuard<'a, DebugRawRwLock, T>; + /// Dependency tracking RwLock. See: [`parking_lot::RwLock`]. + pub type RwLock = lock_api::RwLock; + /// Read guard for [`RwLock`]. + pub type RwLockReadGuard<'a, T> = lock_api::RwLockReadGuard<'a, RawRwLock, T>; + /// Upgradable Read guard for [`RwLock`]. + pub type RwLockUpgradableReadGuard<'a, T> = + lock_api::RwLockUpgradableReadGuard<'a, RawRwLock, T>; + /// Write guard for [`RwLock`]. + pub type RwLockWriteGuard<'a, T> = lock_api::RwLockWriteGuard<'a, RawRwLock, T>; + /// RAII guard for `RwLockReadGuard::map`. + pub type MappedRwLockReadGuard<'a, T> = lock_api::MappedRwLockReadGuard<'a, RawRwLock, T>; + /// RAII guard for `RwLockWriteGuard::map`. + pub type MappedRwLockWriteGuard<'a, T> = lock_api::MappedRwLockWriteGuard<'a, RawRwLock, T>; -/// A dependency-tracking wrapper for [`parking_lot::Once`]. -#[derive(Debug, Default)] -pub struct TracingOnce { - inner: Once, - id: LazyMutexId, -} + /// A dependency-tracking wrapper for [`parking_lot::Once`]. + #[derive(Debug, Default)] + pub struct Once { + inner: parking_lot::Once, + id: LazyMutexId, + } -impl TracingOnce { - /// Create a new `TracingOnce` value. - pub const fn new() -> Self { - Self { - inner: Once::new(), - id: LazyMutexId::new(), + impl Once { + /// Create a new `Once` value. + pub const fn new() -> Self { + Self { + inner: parking_lot::Once::new(), + id: LazyMutexId::new(), + } + } + + /// Returns the current state of this `Once`. + pub fn state(&self) -> OnceState { + self.inner.state() + } + + /// This call is considered as "locking this `Once`" and it participates in dependency + /// tracking as such. + /// + /// # Panics + /// + /// This method will panic if `f` panics, poisoning this `Once`. In addition, this function + /// panics when the lock acquisition order is determined to be inconsistent. + pub fn call_once(&self, f: impl FnOnce()) { + let _borrow = self.id.get_borrowed(); + self.inner.call_once(f); + } + + /// Performs the given initialization routine once and only once. + /// + /// This method is identical to [`Once::call_once`] except it ignores poisoning. + pub fn call_once_force(&self, f: impl FnOnce(OnceState)) { + let _borrow = self.id.get_borrowed(); + self.inner.call_once_force(f); } } - - /// Returns the current state of this `Once`. - pub fn state(&self) -> OnceState { - self.inner.state() - } - - /// - /// This call is considered as "locking this `TracingOnce`" and it participates in dependency - /// tracking as such. - /// - /// # Panics - /// - /// This method will panic if `f` panics, poisoning this `Once`. In addition, this function - /// panics when the lock acquisition order is determined to be inconsistent. - pub fn call_once(&self, f: impl FnOnce()) { - let _borrow = self.id.get_borrowed(); - self.inner.call_once(f); - } - - /// Performs the given initialization routine once and only once. - /// - /// This method is identical to [`TracingOnce::call_once`] except it ignores poisoning. - pub fn call_once_force(&self, f: impl FnOnce(OnceState)) { - let _borrow = self.id.get_borrowed(); - self.inner.call_once_force(f); - } } -/// Debug-only `Once`. -/// -/// If debug assertions are enabled this resolves to [`TracingOnce`] and to [`parking_lot::Once`] -/// otherwise. -#[cfg(debug_assertions)] -pub type DebugOnce = TracingOnce; -#[cfg(not(debug_assertions))] -pub type DebugOnce = Once; - #[cfg(test)] mod tests { use std::sync::Arc; use std::thread; - use super::*; + use super::tracing; #[test] fn test_mutex_usage() { - let mutex = Arc::new(TracingMutex::new(())); + let mutex = Arc::new(tracing::Mutex::new(())); let local_lock = mutex.lock(); drop(local_lock); @@ -236,9 +176,9 @@ mod tests { #[should_panic] fn test_mutex_conflict() { let mutexes = [ - TracingMutex::new(()), - TracingMutex::new(()), - TracingMutex::new(()), + tracing::Mutex::new(()), + tracing::Mutex::new(()), + tracing::Mutex::new(()), ]; for i in 0..3 { @@ -249,7 +189,7 @@ mod tests { #[test] fn test_rwlock_usage() { - let lock = Arc::new(TracingRwLock::new(())); + let lock = Arc::new(tracing::RwLock::new(())); let lock2 = Arc::clone(&lock); let _read_lock = lock.read(); @@ -264,19 +204,19 @@ mod tests { #[test] fn test_rwlock_upgradable_read_usage() { - let lock = TracingRwLock::new(()); + let lock = tracing::RwLock::new(()); // Should be able to acquire an upgradable read lock. - let upgradable_guard: TracingRwLockUpgradableReadGuard<'_, _> = lock.upgradable_read(); + let upgradable_guard: tracing::RwLockUpgradableReadGuard<'_, _> = lock.upgradable_read(); // Should be able to upgrade the guard. - let _write_guard: TracingRwLockWriteGuard<'_, _> = - TracingRwLockUpgradableReadGuard::upgrade(upgradable_guard); + let _write_guard: tracing::RwLockWriteGuard<'_, _> = + tracing::RwLockUpgradableReadGuard::upgrade(upgradable_guard); } #[test] fn test_once_usage() { - let once = Arc::new(TracingOnce::new()); + let once = Arc::new(tracing::Once::new()); let once_clone = once.clone(); assert!(!once_clone.state().done());