Implement a wrapper for parking_lot::Once

This commit is contained in:
2021-05-27 22:19:57 +02:00
parent 77cd603363
commit 618a11f940

View File

@@ -1,4 +1,8 @@
use parking_lot::Once;
use parking_lot::OnceState;
use crate::lockapi::TracingWrapper; use crate::lockapi::TracingWrapper;
use crate::LazyMutexId;
macro_rules! debug_variant { macro_rules! debug_variant {
($debug_name:ident, $tracing_name:ident, $normal_name:ty) => { ($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. /// Debug-only dependency tracking fair mutex.
/// ///
/// If debug assertions are enabled this resolves to [`TracingFairMutex`] and to /// 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>; pub type DebugFairMutex<T> = lock_api::Mutex<DebugRawFairMutex, T>;
/// Mutex guard for [`DebugFairMutex`]. /// Mutex guard for [`DebugFairMutex`].
pub type DebugFairMutexGuard<'a, T> = lock_api::MutexGuard<'a, DebugRawFairMutex, T>; 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. /// Debug-only dependency tracking mutex.
/// ///
/// If debug assertions are enabled this resolves to [`TracingMutex`] and to [`parking_lot::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>; pub type DebugMutex<T> = lock_api::Mutex<DebugRawMutex, T>;
/// Mutex guard for [`DebugMutex`]. /// Mutex guard for [`DebugMutex`].
pub type DebugMutexGuard<'a, T> = lock_api::MutexGuard<'a, DebugRawMutex, T>; 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. /// Debug-only dependency tracking reentrant mutex.
/// ///
/// If debug assertions are enabled this resolves to [`TracingReentrantMutex`] and to /// 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> = pub type DebugReentrantMutex<T> =
lock_api::ReentrantMutex<DebugRawMutex, parking_lot::RawThreadId, T>; lock_api::ReentrantMutex<DebugRawMutex, parking_lot::RawThreadId, T>;
/// Mutex guard for [`DebugReentrantMutex`]. /// Mutex guard for [`DebugReentrantMutex`].
pub type DebugReentrantMutexGuard<'a, T> = pub type DebugReentrantMutexGuard<'a, T> =
lock_api::ReentrantMutexGuard<'a, DebugRawMutex, parking_lot::RawThreadId, 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)] #[cfg(test)]
mod tests { mod tests {
use std::sync::Arc; use std::sync::Arc;
@@ -97,4 +153,24 @@ mod tests {
let _second_lock = mutexes[(i + 1) % 3].lock(); 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());
}
} }