From 4f9fe856a25ab29345b90e7725509e9ee38a37be Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:19:41 +0200 Subject: Adding upstream version 1.69.0+dfsg1. Signed-off-by: Daniel Baumann --- vendor/gimli/src/read/lazy.rs | 116 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 vendor/gimli/src/read/lazy.rs (limited to 'vendor/gimli/src/read/lazy.rs') diff --git a/vendor/gimli/src/read/lazy.rs b/vendor/gimli/src/read/lazy.rs new file mode 100644 index 000000000..6138735c8 --- /dev/null +++ b/vendor/gimli/src/read/lazy.rs @@ -0,0 +1,116 @@ +pub(crate) use imp::*; + +#[cfg(not(feature = "std"))] +mod imp { + use alloc::sync::Arc; + use core::sync::atomic::{AtomicPtr, Ordering}; + use core::{mem, ptr}; + + #[derive(Debug, Default)] + pub(crate) struct LazyArc { + // Only written once with a value obtained from `Arc::into_raw`. + // This holds a ref count for the `Arc`, so it is always safe to + // clone the `Arc` given a reference to the `LazyArc`. + value: AtomicPtr, + } + + impl Drop for LazyArc { + fn drop(&mut self) { + let value_ptr = self.value.load(Ordering::Acquire); + if !value_ptr.is_null() { + // SAFETY: all writes to `self.value` are pointers obtained from `Arc::into_raw`. + drop(unsafe { Arc::from_raw(value_ptr) }); + } + } + } + + impl LazyArc { + pub(crate) fn get Result>(&self, f: F) -> Result, E> { + // Clone an `Arc` given a pointer obtained from `Arc::into_raw`. + // SAFETY: `value_ptr` must be a valid pointer obtained from `Arc::into_raw`. + unsafe fn clone_arc_ptr(value_ptr: *const T) -> Arc { + let value = Arc::from_raw(value_ptr); + let clone = Arc::clone(&value); + mem::forget(value); + clone + } + + // Return the existing value if already computed. + // `Ordering::Acquire` is needed so that the content of the loaded `Arc` is + // visible to this thread. + let value_ptr = self.value.load(Ordering::Acquire); + if !value_ptr.is_null() { + // SAFETY: all writes to `self.value` are pointers obtained from `Arc::into_raw`. + return Ok(unsafe { clone_arc_ptr(value_ptr) }); + } + + // Race to compute and set the value. + let value = f().map(Arc::new)?; + let value_ptr = Arc::into_raw(value); + match self.value.compare_exchange( + ptr::null_mut(), + value_ptr as *mut T, + // Success: `Ordering::Release` is needed so that the content of the stored `Arc` + // is visible to other threads. No ordering is required for the null ptr that is + // loaded, but older rust versions (< 1.64) require that its ordering must not + // be weaker than the failure ordering, so we use `Ordering::AcqRel`. + Ordering::AcqRel, + // Failure: `Ordering::Acquire` is needed so that the content of the loaded `Arc` + // is visible to this thread. + Ordering::Acquire, + ) { + Ok(_) => { + // Return the value we computed. + // SAFETY: `value_ptr` was obtained from `Arc::into_raw`. + Ok(unsafe { clone_arc_ptr(value_ptr) }) + } + Err(existing_value_ptr) => { + // We lost the race, drop unneeded `value_ptr`. + // SAFETY: `value_ptr` was obtained from `Arc::into_raw`. + drop(unsafe { Arc::from_raw(value_ptr) }); + // Return the existing value. + // SAFETY: all writes to `self.value` are pointers obtained from `Arc::into_raw`. + Ok(unsafe { clone_arc_ptr(existing_value_ptr) }) + } + } + } + } +} + +#[cfg(feature = "std")] +mod imp { + use std::sync::{Arc, Mutex}; + + #[derive(Debug, Default)] + pub(crate) struct LazyArc { + value: Mutex>>, + } + + impl LazyArc { + pub(crate) fn get Result>(&self, f: F) -> Result, E> { + let mut lock = self.value.lock().unwrap(); + if let Some(value) = &*lock { + return Ok(value.clone()); + } + let value = f().map(Arc::new)?; + *lock = Some(value.clone()); + Ok(value) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn lazy_arc() { + let lazy = LazyArc::default(); + let value = lazy.get(|| Err(())); + assert_eq!(value, Err(())); + let value = lazy.get(|| Ok::(3)).unwrap(); + assert_eq!(*value, 3); + let value = lazy.get(|| Err(())).unwrap(); + assert_eq!(*value, 3); + } +} -- cgit v1.2.3