diff options
Diffstat (limited to 'vendor/once_cell/src/imp_std.rs')
-rw-r--r-- | vendor/once_cell/src/imp_std.rs | 415 |
1 files changed, 0 insertions, 415 deletions
diff --git a/vendor/once_cell/src/imp_std.rs b/vendor/once_cell/src/imp_std.rs deleted file mode 100644 index 3b9e6d2..0000000 --- a/vendor/once_cell/src/imp_std.rs +++ /dev/null @@ -1,415 +0,0 @@ -// There's a lot of scary concurrent code in this module, but it is copied from -// `std::sync::Once` with two changes: -// * no poisoning -// * init function can fail - -use std::{ - cell::{Cell, UnsafeCell}, - panic::{RefUnwindSafe, UnwindSafe}, - sync::atomic::{AtomicBool, AtomicPtr, Ordering}, - thread::{self, Thread}, -}; - -#[derive(Debug)] -pub(crate) struct OnceCell<T> { - // This `queue` field is the core of the implementation. It encodes two - // pieces of information: - // - // * The current state of the cell (`INCOMPLETE`, `RUNNING`, `COMPLETE`) - // * Linked list of threads waiting for the current cell. - // - // State is encoded in two low bits. Only `INCOMPLETE` and `RUNNING` states - // allow waiters. - queue: AtomicPtr<Waiter>, - value: UnsafeCell<Option<T>>, -} - -// Why do we need `T: Send`? -// Thread A creates a `OnceCell` and shares it with -// scoped thread B, which fills the cell, which is -// then destroyed by A. That is, destructor observes -// a sent value. -unsafe impl<T: Sync + Send> Sync for OnceCell<T> {} -unsafe impl<T: Send> Send for OnceCell<T> {} - -impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceCell<T> {} -impl<T: UnwindSafe> UnwindSafe for OnceCell<T> {} - -impl<T> OnceCell<T> { - pub(crate) const fn new() -> OnceCell<T> { - OnceCell { queue: AtomicPtr::new(INCOMPLETE_PTR), value: UnsafeCell::new(None) } - } - - pub(crate) const fn with_value(value: T) -> OnceCell<T> { - OnceCell { queue: AtomicPtr::new(COMPLETE_PTR), value: UnsafeCell::new(Some(value)) } - } - - /// Safety: synchronizes with store to value via Release/(Acquire|SeqCst). - #[inline] - pub(crate) fn is_initialized(&self) -> bool { - // An `Acquire` load is enough because that makes all the initialization - // operations visible to us, and, this being a fast path, weaker - // ordering helps with performance. This `Acquire` synchronizes with - // `SeqCst` operations on the slow path. - self.queue.load(Ordering::Acquire) == COMPLETE_PTR - } - - /// Safety: synchronizes with store to value via SeqCst read from state, - /// writes value only once because we never get to INCOMPLETE state after a - /// successful write. - #[cold] - pub(crate) fn initialize<F, E>(&self, f: F) -> Result<(), E> - where - F: FnOnce() -> Result<T, E>, - { - let mut f = Some(f); - let mut res: Result<(), E> = Ok(()); - let slot: *mut Option<T> = self.value.get(); - initialize_or_wait( - &self.queue, - Some(&mut || { - let f = unsafe { f.take().unwrap_unchecked() }; - match f() { - Ok(value) => { - unsafe { *slot = Some(value) }; - true - } - Err(err) => { - res = Err(err); - false - } - } - }), - ); - res - } - - #[cold] - pub(crate) fn wait(&self) { - initialize_or_wait(&self.queue, None); - } - - /// Get the reference to the underlying value, without checking if the cell - /// is initialized. - /// - /// # Safety - /// - /// Caller must ensure that the cell is in initialized state, and that - /// the contents are acquired by (synchronized to) this thread. - pub(crate) unsafe fn get_unchecked(&self) -> &T { - debug_assert!(self.is_initialized()); - let slot = &*self.value.get(); - slot.as_ref().unwrap_unchecked() - } - - /// Gets the mutable reference to the underlying value. - /// Returns `None` if the cell is empty. - pub(crate) fn get_mut(&mut self) -> Option<&mut T> { - // Safe b/c we have a unique access. - unsafe { &mut *self.value.get() }.as_mut() - } - - /// Consumes this `OnceCell`, returning the wrapped value. - /// Returns `None` if the cell was empty. - #[inline] - pub(crate) fn into_inner(self) -> Option<T> { - // Because `into_inner` takes `self` by value, the compiler statically - // verifies that it is not currently borrowed. - // So, it is safe to move out `Option<T>`. - self.value.into_inner() - } -} - -// Three states that a OnceCell can be in, encoded into the lower bits of `queue` in -// the OnceCell structure. -const INCOMPLETE: usize = 0x0; -const RUNNING: usize = 0x1; -const COMPLETE: usize = 0x2; -const INCOMPLETE_PTR: *mut Waiter = INCOMPLETE as *mut Waiter; -const COMPLETE_PTR: *mut Waiter = COMPLETE as *mut Waiter; - -// Mask to learn about the state. All other bits are the queue of waiters if -// this is in the RUNNING state. -const STATE_MASK: usize = 0x3; - -/// Representation of a node in the linked list of waiters in the RUNNING state. -/// A waiters is stored on the stack of the waiting threads. -#[repr(align(4))] // Ensure the two lower bits are free to use as state bits. -struct Waiter { - thread: Cell<Option<Thread>>, - signaled: AtomicBool, - next: *mut Waiter, -} - -/// Drains and notifies the queue of waiters on drop. -struct Guard<'a> { - queue: &'a AtomicPtr<Waiter>, - new_queue: *mut Waiter, -} - -impl Drop for Guard<'_> { - fn drop(&mut self) { - let queue = self.queue.swap(self.new_queue, Ordering::AcqRel); - - let state = strict::addr(queue) & STATE_MASK; - assert_eq!(state, RUNNING); - - unsafe { - let mut waiter = strict::map_addr(queue, |q| q & !STATE_MASK); - while !waiter.is_null() { - let next = (*waiter).next; - let thread = (*waiter).thread.take().unwrap(); - (*waiter).signaled.store(true, Ordering::Release); - waiter = next; - thread.unpark(); - } - } - } -} - -// Corresponds to `std::sync::Once::call_inner`. -// -// Originally copied from std, but since modified to remove poisoning and to -// support wait. -// -// Note: this is intentionally monomorphic -#[inline(never)] -fn initialize_or_wait(queue: &AtomicPtr<Waiter>, mut init: Option<&mut dyn FnMut() -> bool>) { - let mut curr_queue = queue.load(Ordering::Acquire); - - loop { - let curr_state = strict::addr(curr_queue) & STATE_MASK; - match (curr_state, &mut init) { - (COMPLETE, _) => return, - (INCOMPLETE, Some(init)) => { - let exchange = queue.compare_exchange( - curr_queue, - strict::map_addr(curr_queue, |q| (q & !STATE_MASK) | RUNNING), - Ordering::Acquire, - Ordering::Acquire, - ); - if let Err(new_queue) = exchange { - curr_queue = new_queue; - continue; - } - let mut guard = Guard { queue, new_queue: INCOMPLETE_PTR }; - if init() { - guard.new_queue = COMPLETE_PTR; - } - return; - } - (INCOMPLETE, None) | (RUNNING, _) => { - wait(queue, curr_queue); - curr_queue = queue.load(Ordering::Acquire); - } - _ => debug_assert!(false), - } - } -} - -fn wait(queue: &AtomicPtr<Waiter>, mut curr_queue: *mut Waiter) { - let curr_state = strict::addr(curr_queue) & STATE_MASK; - loop { - let node = Waiter { - thread: Cell::new(Some(thread::current())), - signaled: AtomicBool::new(false), - next: strict::map_addr(curr_queue, |q| q & !STATE_MASK), - }; - let me = &node as *const Waiter as *mut Waiter; - - let exchange = queue.compare_exchange( - curr_queue, - strict::map_addr(me, |q| q | curr_state), - Ordering::Release, - Ordering::Relaxed, - ); - if let Err(new_queue) = exchange { - if strict::addr(new_queue) & STATE_MASK != curr_state { - return; - } - curr_queue = new_queue; - continue; - } - - while !node.signaled.load(Ordering::Acquire) { - thread::park(); - } - break; - } -} - -// Polyfill of strict provenance from https://crates.io/crates/sptr. -// -// Use free-standing function rather than a trait to keep things simple and -// avoid any potential conflicts with future stabile std API. -mod strict { - #[must_use] - #[inline] - pub(crate) fn addr<T>(ptr: *mut T) -> usize - where - T: Sized, - { - // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. - // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the - // provenance). - unsafe { core::mem::transmute(ptr) } - } - - #[must_use] - #[inline] - pub(crate) fn with_addr<T>(ptr: *mut T, addr: usize) -> *mut T - where - T: Sized, - { - // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. - // - // In the mean-time, this operation is defined to be "as if" it was - // a wrapping_offset, so we can emulate it as such. This should properly - // restore pointer provenance even under today's compiler. - let self_addr = self::addr(ptr) as isize; - let dest_addr = addr as isize; - let offset = dest_addr.wrapping_sub(self_addr); - - // This is the canonical desugarring of this operation, - // but `pointer::cast` was only stabilized in 1.38. - // self.cast::<u8>().wrapping_offset(offset).cast::<T>() - (ptr as *mut u8).wrapping_offset(offset) as *mut T - } - - #[must_use] - #[inline] - pub(crate) fn map_addr<T>(ptr: *mut T, f: impl FnOnce(usize) -> usize) -> *mut T - where - T: Sized, - { - self::with_addr(ptr, f(addr(ptr))) - } -} - -// These test are snatched from std as well. -#[cfg(test)] -mod tests { - use std::panic; - use std::{sync::mpsc::channel, thread}; - - use super::OnceCell; - - impl<T> OnceCell<T> { - fn init(&self, f: impl FnOnce() -> T) { - enum Void {} - let _ = self.initialize(|| Ok::<T, Void>(f())); - } - } - - #[test] - fn smoke_once() { - static O: OnceCell<()> = OnceCell::new(); - let mut a = 0; - O.init(|| a += 1); - assert_eq!(a, 1); - O.init(|| a += 1); - assert_eq!(a, 1); - } - - #[test] - fn stampede_once() { - static O: OnceCell<()> = OnceCell::new(); - static mut RUN: bool = false; - - let (tx, rx) = channel(); - for _ in 0..10 { - let tx = tx.clone(); - thread::spawn(move || { - for _ in 0..4 { - thread::yield_now() - } - unsafe { - O.init(|| { - assert!(!RUN); - RUN = true; - }); - assert!(RUN); - } - tx.send(()).unwrap(); - }); - } - - unsafe { - O.init(|| { - assert!(!RUN); - RUN = true; - }); - assert!(RUN); - } - - for _ in 0..10 { - rx.recv().unwrap(); - } - } - - #[test] - fn poison_bad() { - static O: OnceCell<()> = OnceCell::new(); - - // poison the once - let t = panic::catch_unwind(|| { - O.init(|| panic!()); - }); - assert!(t.is_err()); - - // we can subvert poisoning, however - let mut called = false; - O.init(|| { - called = true; - }); - assert!(called); - - // once any success happens, we stop propagating the poison - O.init(|| {}); - } - - #[test] - fn wait_for_force_to_finish() { - static O: OnceCell<()> = OnceCell::new(); - - // poison the once - let t = panic::catch_unwind(|| { - O.init(|| panic!()); - }); - assert!(t.is_err()); - - // make sure someone's waiting inside the once via a force - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - let t1 = thread::spawn(move || { - O.init(|| { - tx1.send(()).unwrap(); - rx2.recv().unwrap(); - }); - }); - - rx1.recv().unwrap(); - - // put another waiter on the once - let t2 = thread::spawn(|| { - let mut called = false; - O.init(|| { - called = true; - }); - assert!(!called); - }); - - tx2.send(()).unwrap(); - - assert!(t1.join().is_ok()); - assert!(t2.join().is_ok()); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn test_size() { - use std::mem::size_of; - - assert_eq!(size_of::<OnceCell<u32>>(), 4 * size_of::<u32>()); - } -} |