mirror of
https://github.com/bertptrs/tracing-mutex.git
synced 2025-12-25 20:50:32 +01:00
Implement a wrapper for parking_lot::Once
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
use parking_lot::Once;
|
||||
use parking_lot::OnceState;
|
||||
|
||||
use crate::lockapi::TracingWrapper;
|
||||
use crate::LazyMutexId;
|
||||
|
||||
macro_rules! debug_variant {
|
||||
($debug_name:ident, $tracing_name:ident, $normal_name:ty) => {
|
||||
@@ -25,7 +29,7 @@ pub type TracingFairMutexGuard<'a, T> = lock_api::MutexGuard<'a, TracingRawFairM
|
||||
/// Debug-only dependency tracking fair mutex.
|
||||
///
|
||||
/// If debug assertions are enabled this resolves to [`TracingFairMutex`] and to
|
||||
/// [`parking_lot::FairMutex`] if it's not.
|
||||
/// [`parking_lot::FairMutex`] otherwise.
|
||||
pub type DebugFairMutex<T> = lock_api::Mutex<DebugRawFairMutex, T>;
|
||||
/// Mutex guard for [`DebugFairMutex`].
|
||||
pub type DebugFairMutexGuard<'a, T> = lock_api::MutexGuard<'a, DebugRawFairMutex, T>;
|
||||
@@ -37,7 +41,7 @@ pub type TracingMutexGuard<'a, T> = lock_api::MutexGuard<'a, TracingRawMutex, T>
|
||||
/// Debug-only dependency tracking mutex.
|
||||
///
|
||||
/// If debug assertions are enabled this resolves to [`TracingMutex`] and to [`parking_lot::Mutex`]
|
||||
/// if it's not.
|
||||
/// otherwise.
|
||||
pub type DebugMutex<T> = lock_api::Mutex<DebugRawMutex, T>;
|
||||
/// Mutex guard for [`DebugMutex`].
|
||||
pub type DebugMutexGuard<'a, T> = lock_api::MutexGuard<'a, DebugRawMutex, T>;
|
||||
@@ -56,13 +60,65 @@ pub type TracingReentrantMutexGuard<'a, T> = lock_api::ReentrantMutexGuard<
|
||||
/// Debug-only dependency tracking reentrant mutex.
|
||||
///
|
||||
/// If debug assertions are enabled this resolves to [`TracingReentrantMutex`] and to
|
||||
/// [`parking_lot::ReentrantMutex`] if it's not.
|
||||
/// [`parking_lot::ReentrantMutex`] otherwise.
|
||||
pub type DebugReentrantMutex<T> =
|
||||
lock_api::ReentrantMutex<DebugRawMutex, parking_lot::RawThreadId, T>;
|
||||
/// Mutex guard for [`DebugReentrantMutex`].
|
||||
pub type DebugReentrantMutexGuard<'a, T> =
|
||||
lock_api::ReentrantMutexGuard<'a, DebugRawMutex, parking_lot::RawThreadId, T>;
|
||||
|
||||
/// A dependency-tracking wrapper for [`parking_lot::Once`].
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TracingOnce {
|
||||
inner: Once,
|
||||
id: LazyMutexId,
|
||||
}
|
||||
|
||||
impl TracingOnce {
|
||||
/// Create a new `TracingOnce` value.
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
inner: 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 `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 routeine once and only once.
|
||||
///
|
||||
/// This method is identical to [`TracingOnce::call_once`] except it ignores poisining.
|
||||
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;
|
||||
@@ -97,4 +153,24 @@ mod tests {
|
||||
let _second_lock = mutexes[(i + 1) % 3].lock();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_once_usage() {
|
||||
let once = Arc::new(TracingOnce::new());
|
||||
let once_clone = once.clone();
|
||||
|
||||
assert!(!once_clone.state().done());
|
||||
|
||||
let handle = thread::spawn(move || {
|
||||
assert!(!once_clone.state().done());
|
||||
|
||||
once_clone.call_once(|| {});
|
||||
|
||||
assert!(once_clone.state().done());
|
||||
});
|
||||
|
||||
handle.join().unwrap();
|
||||
|
||||
assert!(once.state().done());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user