| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- use crate::{Relax, SpinRelax};
- use core::{
- cell::UnsafeCell,
- marker::PhantomData,
- ops::Deref,
- sync::atomic::{AtomicU8, Ordering},
- };
- enum LazyState<T, F>
- where
- F: FnOnce() -> T,
- {
- Uninitialized(F),
- Initializing,
- Initialized(T),
- }
- pub struct LazyLock<T, F = fn() -> T, R = SpinRelax>
- where
- F: FnOnce() -> T,
- R: Relax,
- {
- value: UnsafeCell<LazyState<T, F>>,
- state: AtomicU8,
- _phantom: PhantomData<R>,
- }
- unsafe impl<T, F, R> Sync for LazyLock<T, F, R>
- where
- T: Send + Sync,
- F: FnOnce() -> T,
- F: Send,
- R: Relax,
- {
- }
- impl<T, F, R> LazyLock<T, F, R>
- where
- F: FnOnce() -> T,
- R: Relax,
- {
- const UNINITIALIZED: u8 = 0;
- const INITIALIZING: u8 = 1;
- const INITIALIZED: u8 = 2;
- pub const fn new(init: F) -> Self {
- Self {
- value: UnsafeCell::new(LazyState::Uninitialized(init)),
- state: AtomicU8::new(Self::UNINITIALIZED),
- _phantom: PhantomData,
- }
- }
- /// # Safety
- /// We should sync with the writer when calling this function or we could read stale data.
- unsafe fn get_initialized_value(&self) -> Option<&T> {
- // SAFETY: We're synced with the cpu that initialized it.
- if let LazyState::Initialized(value) = unsafe { &*self.value.get() } {
- Some(value)
- } else {
- None
- }
- }
- /// Does the initialization of the value and leave `self.state` untouched. The caller
- /// should set the state to `INITIALIZED` after calling this function.
- ///
- /// # Safety
- /// This function is unsafe because concurrent calls would result in undefined behavior.
- /// We should call this function exactly once with `self.state == INITIALIZING`.
- unsafe fn do_initialization(&self) {
- // SAFETY: We are the only thread that can access the value initializer.
- let stateref = unsafe { &mut *self.value.get() };
- let mut state = LazyState::Initializing;
- core::mem::swap(stateref, &mut state);
- if let LazyState::Uninitialized(init_func) = state {
- state = LazyState::Initialized(init_func());
- } else {
- unreachable!("Invalid LazyLock state.");
- };
- core::mem::swap(stateref, &mut state);
- }
- /// Spin until the value is initialized. Guarantees that the initialized value is
- /// visible to the caller cpu.
- fn spin_until_initialized(&self) {
- while self.state.load(Ordering::Acquire) != Self::INITIALIZED {
- R::relax();
- }
- }
- /// Get immutable reference to the wrapped value if initialized. Block until
- /// the value is initialized by someone (including the caller itself) otherwise.
- pub fn get(&self) -> &T {
- match self.state.load(Ordering::Acquire) {
- Self::UNINITIALIZED => match self.state.compare_exchange(
- Self::UNINITIALIZED,
- Self::INITIALIZING,
- Ordering::Acquire,
- Ordering::Acquire,
- ) {
- Ok(_) => unsafe {
- // SAFETY: We are the only thread doing initialization.
- self.do_initialization();
- self.state.store(Self::INITIALIZED, Ordering::Release);
- },
- Err(Self::INITIALIZING) => self.spin_until_initialized(),
- Err(Self::INITIALIZED) => {}
- Err(_) => unreachable!("Invalid LazyLock state."),
- },
- Self::INITIALIZING => self.spin_until_initialized(),
- Self::INITIALIZED => {}
- _ => unreachable!("Invalid LazyLock state."),
- }
- unsafe {
- // SAFETY: If we're the spin waiter, we're synced with the cpu that initialized
- // it using `Acquire`. If we're the one that initialized it, no
- // synchronization is needed.
- self.get_initialized_value()
- .expect("Value should be initialized.")
- }
- }
- pub fn get_mut(&mut self) -> &mut T {
- match self.state.load(Ordering::Acquire) {
- Self::UNINITIALIZED => {
- self.state.swap(Self::INITIALIZING, Ordering::Acquire);
- // SAFETY: We are the only thread doing initialization.
- unsafe {
- self.do_initialization();
- }
- self.state.store(Self::INITIALIZED, Ordering::Release);
- }
- Self::INITIALIZED => {}
- Self::INITIALIZING => unreachable!("We should be the only one initializing it."),
- _ => unreachable!("Invalid LazyLock state."),
- }
- if let LazyState::Initialized(value) = self.value.get_mut() {
- value
- } else {
- unreachable!("Invalid LazyLock state.");
- }
- }
- }
- impl<T, F, R> Deref for LazyLock<T, F, R>
- where
- F: FnOnce() -> T,
- R: Relax,
- {
- type Target = T;
- fn deref(&self) -> &Self::Target {
- self.get()
- }
- }
- impl<T, U, F, R> AsRef<U> for LazyLock<T, F, R>
- where
- U: ?Sized,
- F: FnOnce() -> T,
- R: Relax,
- <Self as Deref>::Target: AsRef<U>,
- {
- fn as_ref(&self) -> &U {
- self.deref().as_ref()
- }
- }
|