From 20431706a863f92cb37dc512fef6e48d192aaf2c Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:11:38 +0200 Subject: Merging upstream version 1.66.0+dfsg1. Signed-off-by: Daniel Baumann --- vendor/crossbeam-utils/src/sync/mod.rs | 2 + vendor/crossbeam-utils/src/sync/once_lock.rs | 103 ++++++++++++++++++++++++ vendor/crossbeam-utils/src/sync/sharded_lock.rs | 24 +++--- vendor/crossbeam-utils/src/sync/wait_group.rs | 5 +- 4 files changed, 121 insertions(+), 13 deletions(-) create mode 100644 vendor/crossbeam-utils/src/sync/once_lock.rs (limited to 'vendor/crossbeam-utils/src/sync') diff --git a/vendor/crossbeam-utils/src/sync/mod.rs b/vendor/crossbeam-utils/src/sync/mod.rs index eeb740c2c..f9eec71fb 100644 --- a/vendor/crossbeam-utils/src/sync/mod.rs +++ b/vendor/crossbeam-utils/src/sync/mod.rs @@ -4,6 +4,8 @@ //! * [`ShardedLock`], a sharded reader-writer lock with fast concurrent reads. //! * [`WaitGroup`], for synchronizing the beginning or end of some computation. +#[cfg(not(crossbeam_loom))] +mod once_lock; mod parker; #[cfg(not(crossbeam_loom))] mod sharded_lock; diff --git a/vendor/crossbeam-utils/src/sync/once_lock.rs b/vendor/crossbeam-utils/src/sync/once_lock.rs new file mode 100644 index 000000000..c1fefc96c --- /dev/null +++ b/vendor/crossbeam-utils/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 { + 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>, + // Unlike std::sync::OnceLock, we don't need PhantomData here because + // we don't use #[may_dangle]. +} + +unsafe impl Sync for OnceLock {} +unsafe impl Send for OnceLock {} + +impl OnceLock { + /// 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(&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(&self, f: F) + where + F: FnOnce() -> T, + { + let slot = self.value.get().cast::(); + 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::() + } +} + +impl Drop for OnceLock { + fn drop(&mut self) { + if self.is_initialized() { + // SAFETY: The inner value has been initialized + unsafe { self.value.get().cast::().drop_in_place() }; + } + } +} diff --git a/vendor/crossbeam-utils/src/sync/sharded_lock.rs b/vendor/crossbeam-utils/src/sync/sharded_lock.rs index 692653447..b43c55ea4 100644 --- a/vendor/crossbeam-utils/src/sync/sharded_lock.rs +++ b/vendor/crossbeam-utils/src/sync/sharded_lock.rs @@ -9,8 +9,8 @@ use std::sync::{LockResult, PoisonError, TryLockError, TryLockResult}; use std::sync::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; use std::thread::{self, ThreadId}; +use crate::sync::once_lock::OnceLock; use crate::CachePadded; -use once_cell::sync::Lazy; /// The number of shards per sharded lock. Must be a power of two. const NUM_SHARDS: usize = 8; @@ -583,13 +583,17 @@ struct ThreadIndices { next_index: usize, } -static THREAD_INDICES: Lazy> = Lazy::new(|| { - Mutex::new(ThreadIndices { - mapping: HashMap::new(), - free_list: Vec::new(), - next_index: 0, - }) -}); +fn thread_indices() -> &'static Mutex { + static THREAD_INDICES: OnceLock> = OnceLock::new(); + fn init() -> Mutex { + Mutex::new(ThreadIndices { + mapping: HashMap::new(), + free_list: Vec::new(), + next_index: 0, + }) + } + THREAD_INDICES.get_or_init(init) +} /// A registration of a thread with an index. /// @@ -601,7 +605,7 @@ struct Registration { impl Drop for Registration { fn drop(&mut self) { - let mut indices = THREAD_INDICES.lock().unwrap(); + let mut indices = thread_indices().lock().unwrap(); indices.mapping.remove(&self.thread_id); indices.free_list.push(self.index); } @@ -610,7 +614,7 @@ impl Drop for Registration { thread_local! { static REGISTRATION: Registration = { let thread_id = thread::current().id(); - let mut indices = THREAD_INDICES.lock().unwrap(); + let mut indices = thread_indices().lock().unwrap(); let index = match indices.free_list.pop() { Some(i) => i, diff --git a/vendor/crossbeam-utils/src/sync/wait_group.rs b/vendor/crossbeam-utils/src/sync/wait_group.rs index 4206ee42b..19d607415 100644 --- a/vendor/crossbeam-utils/src/sync/wait_group.rs +++ b/vendor/crossbeam-utils/src/sync/wait_group.rs @@ -1,6 +1,3 @@ -// Necessary for using `Mutex` for conditional variables -#![allow(clippy::mutex_atomic)] - use crate::primitive::sync::{Arc, Condvar, Mutex}; use std::fmt; @@ -42,6 +39,7 @@ use std::fmt; /// /// // Block until all threads have finished their work. /// wg.wait(); +/// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 /// ``` /// /// [`Barrier`]: std::sync::Barrier @@ -100,6 +98,7 @@ impl WaitGroup { /// /// // Block until both threads have reached `wait()`. /// wg.wait(); + /// # std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371 /// ``` pub fn wait(self) { if *self.inner.count.lock().unwrap() == 1 { -- cgit v1.2.3