diff options
Diffstat (limited to '')
-rw-r--r-- | vendor/crossbeam-epoch/src/default.rs | 34 | ||||
-rw-r--r-- | vendor/crossbeam-epoch/src/lib.rs | 2 | ||||
-rw-r--r-- | vendor/crossbeam-epoch/src/sync/mod.rs | 3 | ||||
-rw-r--r-- | vendor/crossbeam-epoch/src/sync/once_lock.rs | 103 |
4 files changed, 128 insertions, 14 deletions
diff --git a/vendor/crossbeam-epoch/src/default.rs b/vendor/crossbeam-epoch/src/default.rs index c2b4852a4..b42c1c7a7 100644 --- a/vendor/crossbeam-epoch/src/default.rs +++ b/vendor/crossbeam-epoch/src/default.rs @@ -8,22 +8,30 @@ use crate::collector::{Collector, LocalHandle}; use crate::guard::Guard; use crate::primitive::thread_local; #[cfg(not(crossbeam_loom))] -use once_cell::sync::Lazy; +use crate::sync::once_lock::OnceLock; -/// The global data for the default garbage collector. -#[cfg(not(crossbeam_loom))] -static COLLECTOR: Lazy<Collector> = Lazy::new(Collector::new); -// FIXME: loom does not currently provide the equivalent of Lazy: -// https://github.com/tokio-rs/loom/issues/263 -#[cfg(crossbeam_loom)] -loom::lazy_static! { - /// The global data for the default garbage collector. - static ref COLLECTOR: Collector = Collector::new(); +fn collector() -> &'static Collector { + #[cfg(not(crossbeam_loom))] + { + /// The global data for the default garbage collector. + static COLLECTOR: OnceLock<Collector> = OnceLock::new(); + COLLECTOR.get_or_init(Collector::new) + } + // FIXME: loom does not currently provide the equivalent of Lazy: + // https://github.com/tokio-rs/loom/issues/263 + #[cfg(crossbeam_loom)] + { + loom::lazy_static! { + /// The global data for the default garbage collector. + static ref COLLECTOR: Collector = Collector::new(); + } + &COLLECTOR + } } thread_local! { /// The per-thread participant for the default garbage collector. - static HANDLE: LocalHandle = COLLECTOR.register(); + static HANDLE: LocalHandle = collector().register(); } /// Pins the current thread. @@ -40,7 +48,7 @@ pub fn is_pinned() -> bool { /// Returns the default global collector. pub fn default_collector() -> &'static Collector { - &COLLECTOR + collector() } #[inline] @@ -50,7 +58,7 @@ where { HANDLE .try_with(|h| f(h)) - .unwrap_or_else(|_| f(&COLLECTOR.register())) + .unwrap_or_else(|_| f(&collector().register())) } #[cfg(all(test, not(crossbeam_loom)))] diff --git a/vendor/crossbeam-epoch/src/lib.rs b/vendor/crossbeam-epoch/src/lib.rs index 4cf982b6b..b432c1f40 100644 --- a/vendor/crossbeam-epoch/src/lib.rs +++ b/vendor/crossbeam-epoch/src/lib.rs @@ -107,7 +107,7 @@ mod primitive { // https://github.com/tokio-rs/loom#handling-loom-api-differences impl<T> UnsafeCell<T> { #[inline] - pub(crate) fn new(data: T) -> UnsafeCell<T> { + pub(crate) const fn new(data: T) -> UnsafeCell<T> { UnsafeCell(::core::cell::UnsafeCell::new(data)) } diff --git a/vendor/crossbeam-epoch/src/sync/mod.rs b/vendor/crossbeam-epoch/src/sync/mod.rs index 5c06e7643..08981be25 100644 --- a/vendor/crossbeam-epoch/src/sync/mod.rs +++ b/vendor/crossbeam-epoch/src/sync/mod.rs @@ -1,4 +1,7 @@ //! Synchronization primitives. pub(crate) mod list; +#[cfg(feature = "std")] +#[cfg(not(crossbeam_loom))] +pub(crate) mod once_lock; pub(crate) mod queue; diff --git a/vendor/crossbeam-epoch/src/sync/once_lock.rs b/vendor/crossbeam-epoch/src/sync/once_lock.rs new file mode 100644 index 000000000..c1fefc96c --- /dev/null +++ b/vendor/crossbeam-epoch/src/sync/once_lock.rs @@ -0,0 +1,103 @@ +// Based on unstable std::sync::OnceLock. +// +// Source: https://github.com/rust-lang/rust/blob/8e9c93df464b7ada3fc7a1c8ccddd9dcb24ee0a0/library/std/src/sync/once_lock.rs + +use core::cell::UnsafeCell; +use core::mem::MaybeUninit; +use core::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Once; + +pub(crate) struct OnceLock<T> { + once: Once, + // Once::is_completed requires Rust 1.43, so use this to track of whether they have been initialized. + is_initialized: AtomicBool, + value: UnsafeCell<MaybeUninit<T>>, + // Unlike std::sync::OnceLock, we don't need PhantomData here because + // we don't use #[may_dangle]. +} + +unsafe impl<T: Sync + Send> Sync for OnceLock<T> {} +unsafe impl<T: Send> Send for OnceLock<T> {} + +impl<T> OnceLock<T> { + /// Creates a new empty cell. + #[must_use] + pub(crate) const fn new() -> Self { + Self { + once: Once::new(), + is_initialized: AtomicBool::new(false), + value: UnsafeCell::new(MaybeUninit::uninit()), + } + } + + /// Gets the contents of the cell, initializing it with `f` if the cell + /// was empty. + /// + /// Many threads may call `get_or_init` concurrently with different + /// initializing functions, but it is guaranteed that only one function + /// will be executed. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and the cell + /// remains uninitialized. + /// + /// It is an error to reentrantly initialize the cell from `f`. The + /// exact outcome is unspecified. Current implementation deadlocks, but + /// this may be changed to a panic in the future. + pub(crate) fn get_or_init<F>(&self, f: F) -> &T + where + F: FnOnce() -> T, + { + // Fast path check + if self.is_initialized() { + // SAFETY: The inner value has been initialized + return unsafe { self.get_unchecked() }; + } + self.initialize(f); + + debug_assert!(self.is_initialized()); + + // SAFETY: The inner value has been initialized + unsafe { self.get_unchecked() } + } + + #[inline] + fn is_initialized(&self) -> bool { + self.is_initialized.load(Ordering::Acquire) + } + + #[cold] + fn initialize<F>(&self, f: F) + where + F: FnOnce() -> T, + { + let slot = self.value.get().cast::<T>(); + let is_initialized = &self.is_initialized; + + self.once.call_once(|| { + let value = f(); + unsafe { + slot.write(value); + } + is_initialized.store(true, Ordering::Release); + }); + } + + /// # Safety + /// + /// The value must be initialized + unsafe fn get_unchecked(&self) -> &T { + debug_assert!(self.is_initialized()); + &*self.value.get().cast::<T>() + } +} + +impl<T> Drop for OnceLock<T> { + fn drop(&mut self) { + if self.is_initialized() { + // SAFETY: The inner value has been initialized + unsafe { self.value.get().cast::<T>().drop_in_place() }; + } + } +} |