lazy_lock.rs - source
Description: Source of the Rust file `library/std/src/sync/lazy_lock.rs`.

#
std/sync/
lazy_lock.rs

    1use super::once::OnceExclusiveState;
    2use crate::cell::UnsafeCell;
    3use crate::mem::ManuallyDrop;
    4use crate::ops::{Deref, DerefMut};
    5use crate::panic::{RefUnwindSafe, UnwindSafe};
    6use crate::sync::Once;
    7use crate::{fmt, ptr};
    8
    9// We use the state of a Once as discriminant value. Upon creation, the state is
    10// "incomplete" and `f` contains the initialization closure. In the first call to
    11// `call_once`, `f` is taken and run. If it succeeds, `value` is set and the state
    12// is changed to "complete". If it panics, the Once is poisoned, so none of the
    13// two fields is initialized.
    14union Data<T, F> {
    15    value: ManuallyDrop<T>,
    16    f: ManuallyDrop<F>,
    17}
    18
    19/// A value which is initialized on the first access.
    20///
    21/// This type is a thread-safe [`LazyCell`], and can be used in statics.
    22/// Since initialization may be called from multiple threads, any
    23/// dereferencing call will block the calling thread if another
    24/// initialization routine is currently running.
    25///
    26/// [`LazyCell`]: crate::cell::LazyCell
    27///
    28/// # Poisoning
    29///
    30/// If the initialization closure passed to [`LazyLock::new`] panics, the lock will be poisoned.
    31/// Once the lock is poisoned, any threads that attempt to access this lock (via a dereference
    32/// or via an explicit call to [`force()`]) will panic.
    33///
    34/// This concept is similar to that of poisoning in the [`std::sync::poison`] module. A key
    35/// difference, however, is that poisoning in `LazyLock` is _unrecoverable_. All future accesses of
    36/// the lock from other threads will panic, whereas a type in [`std::sync::poison`] like
    37/// [`std::sync::poison::Mutex`] allows recovery via [`PoisonError::into_inner()`].
    38///
    39/// [`force()`]: LazyLock::force
    40/// [`std::sync::poison`]: crate::sync::poison
    41/// [`std::sync::poison::Mutex`]: crate::sync::poison::Mutex
    42/// [`PoisonError::into_inner()`]: crate::sync::poison::PoisonError::into_inner
    43///
    44/// # Examples
    45///
    46/// Initialize static variables with `LazyLock`.
    47/// ```
    48/// use std::sync::LazyLock;
    49///
    50/// // Note: static items do not call [`Drop`] on program termination, so this won't be deallocated.
    51/// // this is fine, as the OS can deallocate the terminated program faster than we can free memory
    52/// // but tools like valgrind might report "memory leaks" as it isn't obvious this is intentional.
    53/// static DEEP_THOUGHT: LazyLock<String> = LazyLock::new(|| {
    54/// # mod another_crate {
    55/// #     pub fn great_question() -> String { "42".to_string() }
    56/// # }
    57///     // M3 Ultra takes about 16 million years in --release config
    58///     another_crate::great_question()
    59/// });
    60///
    61/// // The `String` is built, stored in the `LazyLock`, and returned as `&String`.
    62/// let _ = &*DEEP_THOUGHT;
    63/// ```
    64///
    65/// Initialize fields with `LazyLock`.
    66/// ```
    67/// use std::sync::LazyLock;
    68///
    69/// #[derive(Debug)]
    70/// struct UseCellLock {
    71///     number: LazyLock<u32>,
    72/// }
    73/// fn main() {
    74///     let lock: LazyLock<u32> = LazyLock::new(|| 0u32);
    75///
    76///     let data = UseCellLock { number: lock };
    77///     println!("{}", *data.number);
    78/// }
    79/// ```
    80#[stable(feature = "lazy_cell", since = "1.80.0")]
    81pub struct LazyLock<T, F = fn() -> T> {
    82    // FIXME(nonpoison_once): if possible, switch to nonpoison version once it is available
    83    once: Once,
    84    data: UnsafeCell<Data<T, F>>,
    85}
    86
    87impl<T, F: FnOnce() -> T> LazyLock<T, F> {
    88    /// Creates a new lazy value with the given initializing function.
    89    ///
    90    /// # Examples
    91    ///
    92    /// ```
    93    /// use std::sync::LazyLock;
    94    ///
    95    /// let hello = "Hello, World!".to_string();
    96    ///
    97    /// let lazy = LazyLock::new(|| hello.to_uppercase());
    98    ///
    99    /// assert_eq!(&*lazy, "HELLO, WORLD!");
    100    /// ```
    101    #[inline]
    102    #[stable(feature = "lazy_cell", since = "1.80.0")]
    103    #[rustc_const_stable(feature = "lazy_cell", since = "1.80.0")]
    104    pub const fn new(f: F) -> LazyLock<T, F> {
    105        LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) }
    106    }
    107
    108    /// Creates a new lazy value that is already initialized.
    109    #[inline]
    110    #[cfg(test)]
    111    pub(crate) fn preinit(value: T) -> LazyLock<T, F> {
    112        let once = Once::new();
    113        once.call_once(|| {});
    114        LazyLock { once, data: UnsafeCell::new(Data { value: ManuallyDrop::new(value) }) }
    115    }
    116
    117    /// Consumes this `LazyLock` returning the stored value.
    118    ///
    119    /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
    120    ///
    121    /// # Panics
    122    ///
    123    /// Panics if the lock is poisoned.
    124    ///
    125    /// # Examples
    126    ///
    127    /// ```
    128    /// #![feature(lazy_cell_into_inner)]
    129    ///
    130    /// use std::sync::LazyLock;
    131    ///
    132    /// let hello = "Hello, World!".to_string();
    133    ///
    134    /// let lazy = LazyLock::new(|| hello.to_uppercase());
    135    ///
    136    /// assert_eq!(&*lazy, "HELLO, WORLD!");
    137    /// assert_eq!(LazyLock::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string()));
    138    /// ```
    139    #[unstable(feature = "lazy_cell_into_inner", issue = "125623")]
    140    pub fn into_inner(mut this: Self) -> Result<T, F> {
    141        let state = this.once.state();
    142        match state {
    143            OnceExclusiveState::Poisoned => panic_poisoned(),
    144            state => {
    145                let this = ManuallyDrop::new(this);
    146                let data = unsafe { ptr::read(&this.data) }.into_inner();
    147                match state {
    148                    OnceExclusiveState::Incomplete => {
    149                        Err(ManuallyDrop::into_inner(unsafe { data.f }))
    150                    }
    151                    OnceExclusiveState::Complete => {
    152                        Ok(ManuallyDrop::into_inner(unsafe { data.value }))
    153                    }
    154                    OnceExclusiveState::Poisoned => unreachable!(),
    155                }
    156            }
    157        }
    158    }
    159
    160    /// Forces the evaluation of this lazy value and returns a mutable reference to
    161    /// the result.
    162    ///
    163    /// # Panics
    164    ///
    165    /// If the initialization closure panics (the one that is passed to the [`new()`] method), the
    166    /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
    167    /// accesses of the lock (via [`force()`] or a dereference) to panic.
    168    ///
    169    /// [`new()`]: LazyLock::new
    170    /// [`force()`]: LazyLock::force
    171    ///
    172    /// # Examples
    173    ///
    174    /// ```
    175    /// use std::sync::LazyLock;
    176    ///
    177    /// let mut lazy = LazyLock::new(|| 92);
    178    ///
    179    /// let p = LazyLock::force_mut(&mut lazy);
    180    /// assert_eq!(*p, 92);
    181    /// *p = 44;
    182    /// assert_eq!(*lazy, 44);
    183    /// ```
    184    #[inline]
    185    #[stable(feature = "lazy_get", since = "1.94.0")]
    186    pub fn force_mut(this: &mut LazyLock<T, F>) -> &mut T {
    187        #[cold]
    188        /// # Safety
    189        /// May only be called when the state is `Incomplete`.
    190        unsafe fn really_init_mut<T, F: FnOnce() -> T>(this: &mut LazyLock<T, F>) -> &mut T {
    191            struct PoisonOnPanic<'a, T, F>(&'a mut LazyLock<T, F>);
    192            impl<T, F> Drop for PoisonOnPanic<'_, T, F> {
    193                #[inline]
    194                fn drop(&mut self) {
    195                    self.0.once.set_state(OnceExclusiveState::Poisoned);
    196                }
    197            }
    198
    199            // SAFETY: We always poison if the initializer panics (then we never check the data),
    200            // or set the data on success.
    201            let f = unsafe { ManuallyDrop::take(&mut this.data.get_mut().f) };
    202            // INVARIANT: Initiated from mutable reference, don't drop because we read it.
    203            let guard = PoisonOnPanic(this);
    204            let data = f();
    205            guard.0.data.get_mut().value = ManuallyDrop::new(data);
    206            guard.0.once.set_state(OnceExclusiveState::Complete);
    207            core::mem::forget(guard);
    208            // SAFETY: We put the value there above.
    209            unsafe { &mut this.data.get_mut().value }
    210        }
    211
    212        let state = this.once.state();
    213        match state {
    214            OnceExclusiveState::Poisoned => panic_poisoned(),
    215            // SAFETY: The `Once` states we completed the initialization.
    216            OnceExclusiveState::Complete => unsafe { &mut this.data.get_mut().value },
    217            // SAFETY: The state is `Incomplete`.
    218            OnceExclusiveState::Incomplete => unsafe { really_init_mut(this) },
    219        }
    220    }
    221
    222    /// Forces the evaluation of this lazy value and returns a reference to
    223    /// result. This is equivalent to the `Deref` impl, but is explicit.
    224    ///
    225    /// This method will block the calling thread if another initialization
    226    /// routine is currently running.
    227    ///
    228    /// # Panics
    229    ///
    230    /// If the initialization closure panics (the one that is passed to the [`new()`] method), the
    231    /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
    232    /// accesses of the lock (via [`force()`] or a dereference) to panic.
    233    ///
    234    /// [`new()`]: LazyLock::new
    235    /// [`force()`]: LazyLock::force
    236    ///
    237    /// # Examples
    238    ///
    239    /// ```
    240    /// use std::sync::LazyLock;
    241    ///
    242    /// let lazy = LazyLock::new(|| 92);
    243    ///
    244    /// assert_eq!(LazyLock::force(&lazy), &92);
    245    /// assert_eq!(&*lazy, &92);
    246    /// ```
    247    #[inline]
    248    #[stable(feature = "lazy_cell", since = "1.80.0")]
    249    #[rustc_should_not_be_called_on_const_items]
    250    pub fn force(this: &LazyLock<T, F>) -> &T {
    251        this.once.call_once_force(|state| {
    252            if state.is_poisoned() {
    253                panic_poisoned();
    254            }
    255
    256            // SAFETY: `call_once` only runs this closure once, ever.
    257            let data = unsafe { &mut *this.data.get() };
    258            let f = unsafe { ManuallyDrop::take(&mut data.f) };
    259            let value = f();
    260            data.value = ManuallyDrop::new(value);
    261        });
    262
    263        // SAFETY:
    264        // There are four possible scenarios:
    265        // * the closure was called and initialized `value`.
    266        // * the closure was called and panicked, so this point is never reached.
    267        // * the closure was not called, but a previous call initialized `value`.
    268        // * the closure was not called because the Once is poisoned, which we handled above.
    269        // So `value` has definitely been initialized and will not be modified again.
    270        unsafe { &*(*this.data.get()).value }
    271    }
    272}
    273
    274impl<T, F> LazyLock<T, F> {
    275    /// Returns a mutable reference to the value if initialized. Otherwise (if uninitialized or
    276    /// poisoned), returns `None`.
    277    ///
    278    /// # Examples
    279    ///
    280    /// ```
    281    /// use std::sync::LazyLock;
    282    ///
    283    /// let mut lazy = LazyLock::new(|| 92);
    284    ///
    285    /// assert_eq!(LazyLock::get_mut(&mut lazy), None);
    286    /// let _ = LazyLock::force(&lazy);
    287    /// *LazyLock::get_mut(&mut lazy).unwrap() = 44;
    288    /// assert_eq!(*lazy, 44);
    289    /// ```
    290    #[inline]
    291    #[stable(feature = "lazy_get", since = "1.94.0")]
    292    pub fn get_mut(this: &mut LazyLock<T, F>) -> Option<&mut T> {
    293        // `state()` does not perform an atomic load, so prefer it over `is_complete()`.
    294        let state = this.once.state();
    295        match state {
    296            // SAFETY:
    297            // The closure has been run successfully, so `value` has been initialized.
    298            OnceExclusiveState::Complete => Some(unsafe { &mut this.data.get_mut().value }),
    299            _ => None,
    300        }
    301    }
    302
    303    /// Returns a reference to the value if initialized. Otherwise (if uninitialized or poisoned),
    304    /// returns `None`.
    305    ///
    306    /// # Examples
    307    ///
    308    /// ```
    309    /// use std::sync::LazyLock;
    310    ///
    311    /// let lazy = LazyLock::new(|| 92);
    312    ///
    313    /// assert_eq!(LazyLock::get(&lazy), None);
    314    /// let _ = LazyLock::force(&lazy);
    315    /// assert_eq!(LazyLock::get(&lazy), Some(&92));
    316    /// ```
    317    #[inline]
    318    #[stable(feature = "lazy_get", since = "1.94.0")]
    319    #[rustc_should_not_be_called_on_const_items]
    320    pub fn get(this: &LazyLock<T, F>) -> Option<&T> {
    321        if this.once.is_completed() {
    322            // SAFETY:
    323            // The closure has been run successfully, so `value` has been initialized
    324            // and will not be modified again.
    325            Some(unsafe { &(*this.data.get()).value })
    326        } else {
    327            None
    328        }
    329    }
    330}
    331
    332#[stable(feature = "lazy_cell", since = "1.80.0")]
    333impl<T, F> Drop for LazyLock<T, F> {
    334    fn drop(&mut self) {
    335        match self.once.state() {
    336            OnceExclusiveState::Incomplete => unsafe {
    337                ManuallyDrop::drop(&mut self.data.get_mut().f)
    338            },
    339            OnceExclusiveState::Complete => unsafe {
    340                ManuallyDrop::drop(&mut self.data.get_mut().value)
    341            },
    342            OnceExclusiveState::Poisoned => {}
    343        }
    344    }
    345}
    346
    347#[stable(feature = "lazy_cell", since = "1.80.0")]
    348impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
    349    type Target = T;
    350
    351    /// Dereferences the value.
    352    ///
    353    /// This method will block the calling thread if another initialization
    354    /// routine is currently running.
    355    ///
    356    /// # Panics
    357    ///
    358    /// If the initialization closure panics (the one that is passed to the [`new()`] method), the
    359    /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
    360    /// accesses of the lock (via [`force()`] or a dereference) to panic.
    361    ///
    362    /// [`new()`]: LazyLock::new
    363    /// [`force()`]: LazyLock::force
    364    #[inline]
    365    fn deref(&self) -> &T {
    366        LazyLock::force(self)
    367    }
    368}
    369
    370#[stable(feature = "lazy_deref_mut", since = "1.89.0")]
    371impl<T, F: FnOnce() -> T> DerefMut for LazyLock<T, F> {
    372    /// # Panics
    373    ///
    374    /// If the initialization closure panics (the one that is passed to the [`new()`] method), the
    375    /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
    376    /// accesses of the lock (via [`force()`] or a dereference) to panic.
    377    ///
    378    /// [`new()`]: LazyLock::new
    379    /// [`force()`]: LazyLock::force
    380    #[inline]
    381    fn deref_mut(&mut self) -> &mut T {
    382        LazyLock::force_mut(self)
    383    }
    384}
    385
    386#[stable(feature = "lazy_cell", since = "1.80.0")]
    387impl<T: Default> Default for LazyLock<T> {
    388    /// Creates a new lazy value using `Default` as the initializing function.
    389    #[inline]
    390    fn default() -> LazyLock<T> {
    391        LazyLock::new(T::default)
    392    }
    393}
    394
    395#[stable(feature = "lazy_cell", since = "1.80.0")]
    396impl<T: fmt::Debug, F> fmt::Debug for LazyLock<T, F> {
    397    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    398        let mut d = f.debug_tuple("LazyLock");
    399        match LazyLock::get(self) {
    400            Some(v) => d.field(v),
    401            None => d.field(&format_args!("<uninit>")),
    402        };
    403        d.finish()
    404    }
    405}
    406
    407#[cold]
    408#[inline(never)]
    409fn panic_poisoned() -> ! {
    410    panic!("LazyLock instance has previously been poisoned")
    411}
    412
    413// We never create a `&F` from a `&LazyLock<T, F>` so it is fine
    414// to not impl `Sync` for `F`.
    415#[stable(feature = "lazy_cell", since = "1.80.0")]
    416unsafe impl<T: Sync + Send, F: Send> Sync for LazyLock<T, F> {}
    417// auto-derived `Send` impl is OK.
    418
    419#[stable(feature = "lazy_cell", since = "1.80.0")]
    420impl<T: RefUnwindSafe + UnwindSafe, F: UnwindSafe> RefUnwindSafe for LazyLock<T, F> {}
    421#[stable(feature = "lazy_cell", since = "1.80.0")]
    422impl<T: UnwindSafe, F: UnwindSafe> UnwindSafe for LazyLock<T, F> {}