Implement a tracing wrapper for std::sync::Once.

This commit is contained in:
2021-05-13 15:24:41 +02:00
parent 2567a304d9
commit 19973b3919
2 changed files with 138 additions and 1 deletions

View File

@@ -46,11 +46,14 @@
//!
//! [paper]: https://whileydave.com/publications/pk07_jea/
use std::cell::RefCell;
use std::cell::UnsafeCell;
use std::fmt;
use std::ops::Deref;
use std::ops::DerefMut;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use std::sync::Mutex;
use std::sync::Once;
use std::sync::PoisonError;
use lazy_static::lazy_static;
@@ -155,6 +158,51 @@ impl Drop for MutexId {
}
}
/// `const`-compatible version of [`crate::MutexId`].
///
/// This struct can be used similarly to the normal mutex ID, but to be const-compatible its ID is
/// generated on first use. This allows it to be used as the mutex ID for mutexes with a `const`
/// constructor.
struct LazyMutexId {
inner: UnsafeCell<Option<MutexId>>,
setter: Once,
}
impl LazyMutexId {
pub const fn new() -> Self {
Self {
inner: UnsafeCell::new(None),
setter: Once::new(),
}
}
}
impl fmt::Debug for LazyMutexId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.deref())
}
}
unsafe impl Sync for LazyMutexId {}
impl Deref for LazyMutexId {
type Target = MutexId;
fn deref(&self) -> &Self::Target {
self.setter.call_once(|| {
// Safety: this function is only called once, so only one mutable reference should exist
// at a time.
unsafe {
*self.inner.get() = Some(MutexId::new());
}
});
// Safety: after the above Once runs, there are no longer any mutable references, so we can
// hand this out safely.
unsafe { (*self.inner.get()).as_ref().unwrap() }
}
}
#[derive(Debug)]
struct BorrowedMutex<'a>(&'a MutexId);