once_cell/
race.rs

1//! Thread-safe, non-blocking, "first one wins" flavor of `OnceCell`.
2//!
3//! If two threads race to initialize a type from the `race` module, they
4//! don't block, execute initialization function together, but only one of
5//! them stores the result.
6//!
7//! This module does not require `std` feature.
8//!
9//! # Atomic orderings
10//!
11//! All types in this module use `Acquire` and `Release`
12//! [atomic orderings](Ordering) for all their operations. While this is not
13//! strictly necessary for types other than `OnceBox`, it is useful for users as
14//! it allows them to be certain that after `get` or `get_or_init` returns on
15//! one thread, any side-effects caused by the setter thread prior to them
16//! calling `set` or `get_or_init` will be made visible to that thread; without
17//! it, it's possible for it to appear as if they haven't happened yet from the
18//! getter thread's perspective. This is an acceptable tradeoff to make since
19//! `Acquire` and `Release` have very little performance overhead on most
20//! architectures versus `Relaxed`.
21
22#[cfg(not(feature = "portable-atomic"))]
23use core::sync::atomic;
24#[cfg(feature = "portable-atomic")]
25use portable_atomic as atomic;
26
27use atomic::{AtomicPtr, AtomicUsize, Ordering};
28use core::cell::UnsafeCell;
29use core::marker::PhantomData;
30use core::num::NonZeroUsize;
31use core::ptr;
32
33/// A thread-safe cell which can be written to only once.
34#[derive(Default, Debug)]
35pub struct OnceNonZeroUsize {
36    inner: AtomicUsize,
37}
38
39impl OnceNonZeroUsize {
40    /// Creates a new empty cell.
41    #[inline]
42    pub const fn new() -> OnceNonZeroUsize {
43        OnceNonZeroUsize { inner: AtomicUsize::new(0) }
44    }
45
46    /// Gets the underlying value.
47    #[inline]
48    pub fn get(&self) -> Option<NonZeroUsize> {
49        let val = self.inner.load(Ordering::Acquire);
50        NonZeroUsize::new(val)
51    }
52
53    /// Get the reference to the underlying value, without checking if the cell
54    /// is initialized.
55    ///
56    /// # Safety
57    ///
58    /// Caller must ensure that the cell is in initialized state, and that
59    /// the contents are acquired by (synchronized to) this thread.
60    pub unsafe fn get_unchecked(&self) -> NonZeroUsize {
61        let p = self.inner.as_ptr();
62
63        // SAFETY: The caller is responsible for ensuring that the value
64        // was initialized and that the contents have been acquired by
65        // this thread. Assuming that, we can assume there will be no
66        // conflicting writes to the value since the value will never
67        // change once initialized. This relies on the statement in
68        // https://doc.rust-lang.org/1.83.0/core/sync/atomic/ that "(A
69        // `compare_exchange` or `compare_exchange_weak` that does not
70        // succeed is not considered a write."
71        let val = unsafe { p.read() };
72
73        // SAFETY: The caller is responsible for ensuring the value is
74        // initialized and thus not zero.
75        unsafe { NonZeroUsize::new_unchecked(val) }
76    }
77
78    /// Sets the contents of this cell to `value`.
79    ///
80    /// Returns `Ok(())` if the cell was empty and `Err(())` if it was
81    /// full.
82    #[inline]
83    pub fn set(&self, value: NonZeroUsize) -> Result<(), ()> {
84        let exchange =
85            self.inner.compare_exchange(0, value.get(), Ordering::AcqRel, Ordering::Acquire);
86        match exchange {
87            Ok(_) => Ok(()),
88            Err(_) => Err(()),
89        }
90    }
91
92    /// Gets the contents of the cell, initializing it with `f` if the cell was
93    /// empty.
94    ///
95    /// If several threads concurrently run `get_or_init`, more than one `f` can
96    /// be called. However, all threads will return the same value, produced by
97    /// some `f`.
98    pub fn get_or_init<F>(&self, f: F) -> NonZeroUsize
99    where
100        F: FnOnce() -> NonZeroUsize,
101    {
102        enum Void {}
103        match self.get_or_try_init(|| Ok::<NonZeroUsize, Void>(f())) {
104            Ok(val) => val,
105            Err(void) => match void {},
106        }
107    }
108
109    /// Gets the contents of the cell, initializing it with `f` if
110    /// the cell was empty. If the cell was empty and `f` failed, an
111    /// error is returned.
112    ///
113    /// If several threads concurrently run `get_or_init`, more than one `f` can
114    /// be called. However, all threads will return the same value, produced by
115    /// some `f`.
116    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<NonZeroUsize, E>
117    where
118        F: FnOnce() -> Result<NonZeroUsize, E>,
119    {
120        let val = self.inner.load(Ordering::Acquire);
121        match NonZeroUsize::new(val) {
122            Some(it) => Ok(it),
123            None => self.init(f),
124        }
125    }
126
127    #[cold]
128    #[inline(never)]
129    fn init<E>(&self, f: impl FnOnce() -> Result<NonZeroUsize, E>) -> Result<NonZeroUsize, E> {
130        let mut val = f()?.get();
131        let exchange = self.inner.compare_exchange(0, val, Ordering::AcqRel, Ordering::Acquire);
132        if let Err(old) = exchange {
133            val = old;
134        }
135        Ok(unsafe { NonZeroUsize::new_unchecked(val) })
136    }
137}
138
139/// A thread-safe cell which can be written to only once.
140#[derive(Default, Debug)]
141pub struct OnceBool {
142    inner: OnceNonZeroUsize,
143}
144
145impl OnceBool {
146    /// Creates a new empty cell.
147    #[inline]
148    pub const fn new() -> OnceBool {
149        OnceBool { inner: OnceNonZeroUsize::new() }
150    }
151
152    /// Gets the underlying value.
153    #[inline]
154    pub fn get(&self) -> Option<bool> {
155        self.inner.get().map(OnceBool::from_usize)
156    }
157
158    /// Sets the contents of this cell to `value`.
159    ///
160    /// Returns `Ok(())` if the cell was empty and `Err(())` if it was
161    /// full.
162    #[inline]
163    pub fn set(&self, value: bool) -> Result<(), ()> {
164        self.inner.set(OnceBool::to_usize(value))
165    }
166
167    /// Gets the contents of the cell, initializing it with `f` if the cell was
168    /// empty.
169    ///
170    /// If several threads concurrently run `get_or_init`, more than one `f` can
171    /// be called. However, all threads will return the same value, produced by
172    /// some `f`.
173    pub fn get_or_init<F>(&self, f: F) -> bool
174    where
175        F: FnOnce() -> bool,
176    {
177        OnceBool::from_usize(self.inner.get_or_init(|| OnceBool::to_usize(f())))
178    }
179
180    /// Gets the contents of the cell, initializing it with `f` if
181    /// the cell was empty. If the cell was empty and `f` failed, an
182    /// error is returned.
183    ///
184    /// If several threads concurrently run `get_or_init`, more than one `f` can
185    /// be called. However, all threads will return the same value, produced by
186    /// some `f`.
187    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<bool, E>
188    where
189        F: FnOnce() -> Result<bool, E>,
190    {
191        self.inner.get_or_try_init(|| f().map(OnceBool::to_usize)).map(OnceBool::from_usize)
192    }
193
194    #[inline]
195    fn from_usize(value: NonZeroUsize) -> bool {
196        value.get() == 1
197    }
198
199    #[inline]
200    fn to_usize(value: bool) -> NonZeroUsize {
201        unsafe { NonZeroUsize::new_unchecked(if value { 1 } else { 2 }) }
202    }
203}
204
205/// A thread-safe cell which can be written to only once.
206pub struct OnceRef<'a, T> {
207    inner: AtomicPtr<T>,
208    ghost: PhantomData<UnsafeCell<&'a T>>,
209}
210
211// TODO: Replace UnsafeCell with SyncUnsafeCell once stabilized
212unsafe impl<'a, T: Sync> Sync for OnceRef<'a, T> {}
213
214impl<'a, T> core::fmt::Debug for OnceRef<'a, T> {
215    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
216        write!(f, "OnceRef({:?})", self.inner)
217    }
218}
219
220impl<'a, T> Default for OnceRef<'a, T> {
221    fn default() -> Self {
222        Self::new()
223    }
224}
225
226impl<'a, T> OnceRef<'a, T> {
227    /// Creates a new empty cell.
228    pub const fn new() -> OnceRef<'a, T> {
229        OnceRef { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData }
230    }
231
232    /// Gets a reference to the underlying value.
233    pub fn get(&self) -> Option<&'a T> {
234        let ptr = self.inner.load(Ordering::Acquire);
235        unsafe { ptr.as_ref() }
236    }
237
238    /// Sets the contents of this cell to `value`.
239    ///
240    /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was
241    /// full.
242    pub fn set(&self, value: &'a T) -> Result<(), ()> {
243        let ptr = value as *const T as *mut T;
244        let exchange =
245            self.inner.compare_exchange(ptr::null_mut(), ptr, Ordering::AcqRel, Ordering::Acquire);
246        match exchange {
247            Ok(_) => Ok(()),
248            Err(_) => Err(()),
249        }
250    }
251
252    /// Gets the contents of the cell, initializing it with `f` if the cell was
253    /// empty.
254    ///
255    /// If several threads concurrently run `get_or_init`, more than one `f` can
256    /// be called. However, all threads will return the same value, produced by
257    /// some `f`.
258    pub fn get_or_init<F>(&self, f: F) -> &'a T
259    where
260        F: FnOnce() -> &'a T,
261    {
262        enum Void {}
263        match self.get_or_try_init(|| Ok::<&'a T, Void>(f())) {
264            Ok(val) => val,
265            Err(void) => match void {},
266        }
267    }
268
269    /// Gets the contents of the cell, initializing it with `f` if
270    /// the cell was empty. If the cell was empty and `f` failed, an
271    /// error is returned.
272    ///
273    /// If several threads concurrently run `get_or_init`, more than one `f` can
274    /// be called. However, all threads will return the same value, produced by
275    /// some `f`.
276    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&'a T, E>
277    where
278        F: FnOnce() -> Result<&'a T, E>,
279    {
280        let mut ptr = self.inner.load(Ordering::Acquire);
281
282        if ptr.is_null() {
283            // TODO replace with `cast_mut` when MSRV reaches 1.65.0 (also in `set`)
284            ptr = f()? as *const T as *mut T;
285            let exchange = self.inner.compare_exchange(
286                ptr::null_mut(),
287                ptr,
288                Ordering::AcqRel,
289                Ordering::Acquire,
290            );
291            if let Err(old) = exchange {
292                ptr = old;
293            }
294        }
295
296        Ok(unsafe { &*ptr })
297    }
298
299    /// ```compile_fail
300    /// use once_cell::race::OnceRef;
301    ///
302    /// let mut l = OnceRef::new();
303    ///
304    /// {
305    ///     let y = 2;
306    ///     let mut r = OnceRef::new();
307    ///     r.set(&y).unwrap();
308    ///     core::mem::swap(&mut l, &mut r);
309    /// }
310    ///
311    /// // l now contains a dangling reference to y
312    /// eprintln!("uaf: {}", l.get().unwrap());
313    /// ```
314    fn _dummy() {}
315}
316
317#[cfg(feature = "alloc")]
318pub use self::once_box::OnceBox;
319
320#[cfg(feature = "alloc")]
321mod once_box {
322    use super::atomic::{AtomicPtr, Ordering};
323    use core::{marker::PhantomData, ptr};
324
325    use alloc::boxed::Box;
326
327    /// A thread-safe cell which can be written to only once.
328    pub struct OnceBox<T> {
329        inner: AtomicPtr<T>,
330        ghost: PhantomData<Option<Box<T>>>,
331    }
332
333    impl<T> core::fmt::Debug for OnceBox<T> {
334        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
335            write!(f, "OnceBox({:?})", self.inner.load(Ordering::Relaxed))
336        }
337    }
338
339    impl<T> Default for OnceBox<T> {
340        fn default() -> Self {
341            Self::new()
342        }
343    }
344
345    impl<T> Drop for OnceBox<T> {
346        fn drop(&mut self) {
347            let ptr = *self.inner.get_mut();
348            if !ptr.is_null() {
349                drop(unsafe { Box::from_raw(ptr) })
350            }
351        }
352    }
353
354    impl<T> OnceBox<T> {
355        /// Creates a new empty cell.
356        pub const fn new() -> OnceBox<T> {
357            OnceBox { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData }
358        }
359
360        /// Creates a new cell with the given value.
361        pub fn with_value(value: Box<T>) -> Self {
362            OnceBox { inner: AtomicPtr::new(Box::into_raw(value)), ghost: PhantomData }
363        }
364
365        /// Gets a reference to the underlying value.
366        pub fn get(&self) -> Option<&T> {
367            let ptr = self.inner.load(Ordering::Acquire);
368            if ptr.is_null() {
369                return None;
370            }
371            Some(unsafe { &*ptr })
372        }
373
374        /// Sets the contents of this cell to `value`.
375        ///
376        /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was
377        /// full.
378        pub fn set(&self, value: Box<T>) -> Result<(), Box<T>> {
379            let ptr = Box::into_raw(value);
380            let exchange = self.inner.compare_exchange(
381                ptr::null_mut(),
382                ptr,
383                Ordering::AcqRel,
384                Ordering::Acquire,
385            );
386            if exchange.is_err() {
387                let value = unsafe { Box::from_raw(ptr) };
388                return Err(value);
389            }
390            Ok(())
391        }
392
393        /// Gets the contents of the cell, initializing it with `f` if the cell was
394        /// empty.
395        ///
396        /// If several threads concurrently run `get_or_init`, more than one `f` can
397        /// be called. However, all threads will return the same value, produced by
398        /// some `f`.
399        pub fn get_or_init<F>(&self, f: F) -> &T
400        where
401            F: FnOnce() -> Box<T>,
402        {
403            enum Void {}
404            match self.get_or_try_init(|| Ok::<Box<T>, Void>(f())) {
405                Ok(val) => val,
406                Err(void) => match void {},
407            }
408        }
409
410        /// Gets the contents of the cell, initializing it with `f` if
411        /// the cell was empty. If the cell was empty and `f` failed, an
412        /// error is returned.
413        ///
414        /// If several threads concurrently run `get_or_init`, more than one `f` can
415        /// be called. However, all threads will return the same value, produced by
416        /// some `f`.
417        pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
418        where
419            F: FnOnce() -> Result<Box<T>, E>,
420        {
421            let mut ptr = self.inner.load(Ordering::Acquire);
422
423            if ptr.is_null() {
424                let val = f()?;
425                ptr = Box::into_raw(val);
426                let exchange = self.inner.compare_exchange(
427                    ptr::null_mut(),
428                    ptr,
429                    Ordering::AcqRel,
430                    Ordering::Acquire,
431                );
432                if let Err(old) = exchange {
433                    drop(unsafe { Box::from_raw(ptr) });
434                    ptr = old;
435                }
436            };
437            Ok(unsafe { &*ptr })
438        }
439    }
440
441    unsafe impl<T: Sync + Send> Sync for OnceBox<T> {}
442
443    impl<T: Clone> Clone for OnceBox<T> {
444        fn clone(&self) -> Self {
445            match self.get() {
446                Some(value) => OnceBox::with_value(Box::new(value.clone())),
447                None => OnceBox::new(),
448            }
449        }
450    }
451
452    /// ```compile_fail
453    /// struct S(*mut ());
454    /// unsafe impl Sync for S {}
455    ///
456    /// fn share<T: Sync>(_: &T) {}
457    /// share(&once_cell::race::OnceBox::<S>::new());
458    /// ```
459    fn _dummy() {}
460}