conquer_once/spin.rs
1//! Synchronized one-time and lazy initialization primitives that use spin-locks
2//! in case of concurrent accesses under contention.
3
4use core::{hint, sync::atomic::Ordering};
5
6use crate::{
7 cell::{Block, Unblock},
8 state::{AtomicOnceState, BlockedState, OnceState::WouldBlock},
9 POISON_PANIC_MSG,
10};
11
12use self::internal::Spin;
13
14/// A type for lazy initialization of e.g. global static variables, which
15/// provides the same functionality as the `lazy_static!` macro.
16///
17/// This type uses spin-locks if the initialization is contended and is thus
18/// `#[no_std]` compatible.
19///
20/// For the API of this type alias, see the API of the generic
21/// [`Lazy`](crate::doc::Lazy) type.
22pub type Lazy<T, F = fn() -> T> = crate::lazy::Lazy<T, Spin, F>;
23
24/// An interior mutability cell type which allows synchronized one-time
25/// initialization and read-only access exclusively after initialization.
26///
27/// This type uses spin-locks if the initialization is contended and is thus
28/// `#[no_std]` compatible.
29///
30/// For the API of this type alias, see the generic
31/// [`OnceCell`](crate::doc::OnceCell) type.
32pub type OnceCell<T> = crate::cell::OnceCell<T, Spin>;
33
34/// A synchronization primitive which can be used to run a one-time global
35/// initialization.
36///
37/// This type uses spin-locks if the initialization is contended and is thus
38/// `#[no_std]` compatible.
39///
40/// For the API of this type alias, see the generic
41/// [`OnceCell`](crate::doc::OnceCell) type.
42/// This is a specialization with `T = ()`.
43pub type Once = OnceCell<()>;
44
45mod internal {
46 /// Blocking strategy for blocking threads using spin-locks.
47 #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
48 pub struct Spin;
49}
50
51impl Unblock for Spin {
52 #[inline(always)]
53 unsafe fn on_unblock(_: BlockedState) {}
54}
55
56unsafe impl Block for Spin {
57 /// Spins until the [`OnceCell`] state is set to `READY`, or panics if it
58 /// becomes poisoned.
59 #[inline]
60 fn block(state: &AtomicOnceState) {
61 // (spin:1) this acquire load syncs-with the acq-rel swap (guard:2)
62 while let WouldBlock(_) = state.load(Ordering::Acquire).expect(POISON_PANIC_MSG) {
63 hint::spin_loop();
64 }
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 generate_tests_non_blocking!();
71 generate_tests!();
72}