summaryrefslogtreecommitdiffstats
path: root/vendor/crossbeam-epoch/src
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/crossbeam-epoch/src')
-rw-r--r--vendor/crossbeam-epoch/src/default.rs34
-rw-r--r--vendor/crossbeam-epoch/src/lib.rs2
-rw-r--r--vendor/crossbeam-epoch/src/sync/mod.rs3
-rw-r--r--vendor/crossbeam-epoch/src/sync/once_lock.rs103
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() };
+ }
+ }
+}