kernel/sync/
once.rs

1use core::{
2    cell::UnsafeCell,
3    fmt,
4    marker::PhantomData,
5    mem::MaybeUninit,
6    sync::atomic::{AtomicUsize, Ordering},
7};
8
9const ONCE_STATE_INIT: usize = 0;
10const ONCE_STATE_RUNNING: usize = 1;
11const ONCE_STATE_DONE: usize = 2;
12
13struct Once {
14    state: AtomicUsize,
15}
16
17impl Once {
18    pub const fn new() -> Self {
19        Once {
20            state: AtomicUsize::new(ONCE_STATE_INIT),
21        }
22    }
23
24    #[inline(always)]
25    fn is_completed(&self) -> bool {
26        self.state.load(Ordering::Relaxed) == ONCE_STATE_DONE
27    }
28
29    pub fn call(&self, f: impl FnOnce()) {
30        let mut state = self.state.load(Ordering::Acquire);
31        loop {
32            match state {
33                ONCE_STATE_INIT => {
34                    // Try to transition to RUNNING state.
35                    match self.state.compare_exchange_weak(
36                        ONCE_STATE_INIT,
37                        ONCE_STATE_RUNNING,
38                        Ordering::Acquire,
39                        Ordering::Relaxed,
40                    ) {
41                        Ok(_) => {
42                            // We've successfully transitioned to RUNNING state.
43                            // Run the closure.
44                            f();
45
46                            // Transition to DONE state.
47                            self.state.store(ONCE_STATE_DONE, Ordering::Release);
48                            return;
49                        }
50                        Err(new) => {
51                            // We failed to transition to RUNNING state.
52                            state = new;
53                            continue;
54                        }
55                    }
56                }
57                ONCE_STATE_RUNNING => {
58                    panic!("Once::call already running");
59                }
60                ONCE_STATE_DONE => return,
61                _ => unreachable!("state is never set to invalid values"),
62            }
63        }
64    }
65}
66
67pub struct OnceLock<T> {
68    once: Once,
69    // Whether or not the value is initialized is tracked by `once.is_completed()`.
70    value: UnsafeCell<MaybeUninit<T>>,
71    /// `PhantomData` to make sure dropck understands we're dropping T in our Drop impl.
72    ///
73    /// ```compile_fail,E0597
74    /// use std::sync::OnceLock;
75    ///
76    /// struct A<'a>(&'a str);
77    ///
78    /// impl<'a> Drop for A<'a> {
79    ///     fn drop(&mut self) {}
80    /// }
81    ///
82    /// let cell = OnceLock::new();
83    /// {
84    ///     let s = String::new();
85    ///     let _ = cell.set(A(&s));
86    /// }
87    /// ```
88    _marker: PhantomData<T>,
89}
90
91unsafe impl<T: Sync + Send> Sync for OnceLock<T> {}
92unsafe impl<T: Send> Send for OnceLock<T> {}
93
94impl Default for Once {
95    fn default() -> Self {
96        Self::new()
97    }
98}
99
100impl<T: fmt::Debug> fmt::Debug for OnceLock<T> {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        let mut d = f.debug_tuple("OnceLock");
103        match self.try_get() {
104            Some(v) => d.field(v),
105            None => d.field(&format_args!("<uninit>")),
106        };
107        d.finish()
108    }
109}
110
111impl<T: Clone> Clone for OnceLock<T> {
112    #[inline]
113    fn clone(&self) -> OnceLock<T> {
114        let cell = Self::new();
115        if let Some(value) = self.try_get() {
116            match cell.set(value.clone()) {
117                Ok(()) => (),
118                Err(_) => unreachable!(),
119            }
120        }
121        cell
122    }
123}
124
125#[allow(dead_code)]
126impl<T> OnceLock<T> {
127    pub const fn new() -> Self {
128        OnceLock {
129            once: Once::new(),
130            value: UnsafeCell::new(MaybeUninit::uninit()),
131            _marker: PhantomData,
132        }
133    }
134
135    pub fn set(&self, value: T) -> Result<(), T> {
136        if self.is_completed() {
137            return Err(value);
138        }
139        self.init(|| Ok(value))
140    }
141
142    pub fn get(&self) -> &T {
143        if self.once.is_completed() {
144            unsafe { self.get_unchecked() }
145        } else {
146            panic!("OnceLock::get called before OnceLock::set");
147        }
148    }
149
150    pub fn try_get(&self) -> Option<&T> {
151        if self.once.is_completed() {
152            Some(unsafe { self.get_unchecked() })
153        } else {
154            None
155        }
156    }
157
158    pub fn get_or_init<F>(&self, f: F) -> &T
159    where
160        F: FnOnce() -> T,
161    {
162        match self.get_or_try_init(|| Ok::<T, ()>(f())) {
163            Ok(val) => val,
164            Err(_) => panic!(),
165        }
166    }
167
168    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
169    where
170        F: FnOnce() -> Result<T, E>,
171    {
172        // Fast path check
173        // NOTE: We need to perform an acquire on the state in this method
174        // in order to correctly synchronize `LazyLock::force`. This is
175        // currently done by calling `self.get()`, which in turn calls
176        // `self.is_initialized()`, which in turn performs the acquire.
177        if let Some(value) = self.try_get() {
178            return Ok(value);
179        }
180        self.init(f)?;
181
182        debug_assert!(self.is_completed());
183
184        // SAFETY: The inner value has been initialized
185        Ok(unsafe { self.get_unchecked() })
186    }
187
188    #[cold]
189    fn init<F, E>(&self, f: F) -> Result<(), E>
190    where
191        F: FnOnce() -> Result<T, E>,
192    {
193        let mut res: Result<(), E> = Ok(());
194        let slot = &self.value;
195
196        // Ignore poisoning from other threads
197        // If another thread panics, then we'll be able to run our closure
198        self.once.call(|| match f() {
199            Ok(value) => {
200                unsafe { (*slot.get()).write(value) };
201            }
202            Err(e) => {
203                res = Err(e);
204            }
205        });
206        res
207    }
208
209    unsafe fn get_unchecked(&self) -> &T {
210        debug_assert!(self.once.is_completed());
211        (*self.value.get()).assume_init_ref()
212    }
213
214    fn is_completed(&self) -> bool {
215        self.once.is_completed()
216    }
217}
218
219impl<T> Drop for OnceLock<T> {
220    fn drop(&mut self) {
221        if self.once.is_completed() {
222            unsafe {
223                (*self.value.get()).assume_init_drop();
224            }
225        }
226    }
227}