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(feature = "critical-section")]
23 use portable_atomic as atomic;
24 #[cfg(not(feature = "critical-section"))]
25 use core::sync::atomic;
26 
27 use atomic::{AtomicPtr, AtomicUsize, Ordering};
28 use core::cell::UnsafeCell;
29 use core::marker::PhantomData;
30 use core::num::NonZeroUsize;
31 use core::ptr;
32 
33 /// A thread-safe cell which can be written to only once.
34 #[derive(Default, Debug)]
35 pub struct OnceNonZeroUsize {
36     inner: AtomicUsize,
37 }
38 
39 impl OnceNonZeroUsize {
40     /// Creates a new empty cell.
41     #[inline]
new() -> OnceNonZeroUsize42     pub const fn new() -> OnceNonZeroUsize {
43         OnceNonZeroUsize { inner: AtomicUsize::new(0) }
44     }
45 
46     /// Gets the underlying value.
47     #[inline]
get(&self) -> Option<NonZeroUsize>48     pub fn get(&self) -> Option<NonZeroUsize> {
49         let val = self.inner.load(Ordering::Acquire);
50         NonZeroUsize::new(val)
51     }
52 
53     /// Sets the contents of this cell to `value`.
54     ///
55     /// Returns `Ok(())` if the cell was empty and `Err(())` if it was
56     /// full.
57     #[inline]
set(&self, value: NonZeroUsize) -> Result<(), ()>58     pub fn set(&self, value: NonZeroUsize) -> Result<(), ()> {
59         let exchange =
60             self.inner.compare_exchange(0, value.get(), Ordering::AcqRel, Ordering::Acquire);
61         match exchange {
62             Ok(_) => Ok(()),
63             Err(_) => Err(()),
64         }
65     }
66 
67     /// Gets the contents of the cell, initializing it with `f` if the cell was
68     /// empty.
69     ///
70     /// If several threads concurrently run `get_or_init`, more than one `f` can
71     /// be called. However, all threads will return the same value, produced by
72     /// some `f`.
get_or_init<F>(&self, f: F) -> NonZeroUsize where F: FnOnce() -> NonZeroUsize,73     pub fn get_or_init<F>(&self, f: F) -> NonZeroUsize
74     where
75         F: FnOnce() -> NonZeroUsize,
76     {
77         enum Void {}
78         match self.get_or_try_init(|| Ok::<NonZeroUsize, Void>(f())) {
79             Ok(val) => val,
80             Err(void) => match void {},
81         }
82     }
83 
84     /// Gets the contents of the cell, initializing it with `f` if
85     /// the cell was empty. If the cell was empty and `f` failed, an
86     /// error is returned.
87     ///
88     /// If several threads concurrently run `get_or_init`, more than one `f` can
89     /// be called. However, all threads will return the same value, produced by
90     /// some `f`.
get_or_try_init<F, E>(&self, f: F) -> Result<NonZeroUsize, E> where F: FnOnce() -> Result<NonZeroUsize, E>,91     pub fn get_or_try_init<F, E>(&self, f: F) -> Result<NonZeroUsize, E>
92     where
93         F: FnOnce() -> Result<NonZeroUsize, E>,
94     {
95         let val = self.inner.load(Ordering::Acquire);
96         let res = match NonZeroUsize::new(val) {
97             Some(it) => it,
98             None => {
99                 let mut val = f()?.get();
100                 let exchange =
101                     self.inner.compare_exchange(0, val, Ordering::AcqRel, Ordering::Acquire);
102                 if let Err(old) = exchange {
103                     val = old;
104                 }
105                 unsafe { NonZeroUsize::new_unchecked(val) }
106             }
107         };
108         Ok(res)
109     }
110 }
111 
112 /// A thread-safe cell which can be written to only once.
113 #[derive(Default, Debug)]
114 pub struct OnceBool {
115     inner: OnceNonZeroUsize,
116 }
117 
118 impl OnceBool {
119     /// Creates a new empty cell.
120     #[inline]
new() -> OnceBool121     pub const fn new() -> OnceBool {
122         OnceBool { inner: OnceNonZeroUsize::new() }
123     }
124 
125     /// Gets the underlying value.
126     #[inline]
get(&self) -> Option<bool>127     pub fn get(&self) -> Option<bool> {
128         self.inner.get().map(OnceBool::from_usize)
129     }
130 
131     /// Sets the contents of this cell to `value`.
132     ///
133     /// Returns `Ok(())` if the cell was empty and `Err(())` if it was
134     /// full.
135     #[inline]
set(&self, value: bool) -> Result<(), ()>136     pub fn set(&self, value: bool) -> Result<(), ()> {
137         self.inner.set(OnceBool::to_usize(value))
138     }
139 
140     /// Gets the contents of the cell, initializing it with `f` if the cell was
141     /// empty.
142     ///
143     /// If several threads concurrently run `get_or_init`, more than one `f` can
144     /// be called. However, all threads will return the same value, produced by
145     /// some `f`.
get_or_init<F>(&self, f: F) -> bool where F: FnOnce() -> bool,146     pub fn get_or_init<F>(&self, f: F) -> bool
147     where
148         F: FnOnce() -> bool,
149     {
150         OnceBool::from_usize(self.inner.get_or_init(|| OnceBool::to_usize(f())))
151     }
152 
153     /// Gets the contents of the cell, initializing it with `f` if
154     /// the cell was empty. If the cell was empty and `f` failed, an
155     /// error is returned.
156     ///
157     /// If several threads concurrently run `get_or_init`, more than one `f` can
158     /// be called. However, all threads will return the same value, produced by
159     /// some `f`.
get_or_try_init<F, E>(&self, f: F) -> Result<bool, E> where F: FnOnce() -> Result<bool, E>,160     pub fn get_or_try_init<F, E>(&self, f: F) -> Result<bool, E>
161     where
162         F: FnOnce() -> Result<bool, E>,
163     {
164         self.inner.get_or_try_init(|| f().map(OnceBool::to_usize)).map(OnceBool::from_usize)
165     }
166 
167     #[inline]
from_usize(value: NonZeroUsize) -> bool168     fn from_usize(value: NonZeroUsize) -> bool {
169         value.get() == 1
170     }
171 
172     #[inline]
to_usize(value: bool) -> NonZeroUsize173     fn to_usize(value: bool) -> NonZeroUsize {
174         unsafe { NonZeroUsize::new_unchecked(if value { 1 } else { 2 }) }
175     }
176 }
177 
178 /// A thread-safe cell which can be written to only once.
179 pub struct OnceRef<'a, T> {
180     inner: AtomicPtr<T>,
181     ghost: PhantomData<UnsafeCell<&'a T>>,
182 }
183 
184 // TODO: Replace UnsafeCell with SyncUnsafeCell once stabilized
185 unsafe impl<'a, T: Sync> Sync for OnceRef<'a, T> {}
186 
187 impl<'a, T> core::fmt::Debug for OnceRef<'a, T> {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result188     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
189         write!(f, "OnceRef({:?})", self.inner)
190     }
191 }
192 
193 impl<'a, T> Default for OnceRef<'a, T> {
default() -> Self194     fn default() -> Self {
195         Self::new()
196     }
197 }
198 
199 impl<'a, T> OnceRef<'a, T> {
200     /// Creates a new empty cell.
new() -> OnceRef<'a, T>201     pub const fn new() -> OnceRef<'a, T> {
202         OnceRef { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData }
203     }
204 
205     /// Gets a reference to the underlying value.
get(&self) -> Option<&'a T>206     pub fn get(&self) -> Option<&'a T> {
207         let ptr = self.inner.load(Ordering::Acquire);
208         unsafe { ptr.as_ref() }
209     }
210 
211     /// Sets the contents of this cell to `value`.
212     ///
213     /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was
214     /// full.
set(&self, value: &'a T) -> Result<(), ()>215     pub fn set(&self, value: &'a T) -> Result<(), ()> {
216         let ptr = value as *const T as *mut T;
217         let exchange =
218             self.inner.compare_exchange(ptr::null_mut(), ptr, Ordering::AcqRel, Ordering::Acquire);
219         match exchange {
220             Ok(_) => Ok(()),
221             Err(_) => Err(()),
222         }
223     }
224 
225     /// Gets the contents of the cell, initializing it with `f` if the cell was
226     /// empty.
227     ///
228     /// If several threads concurrently run `get_or_init`, more than one `f` can
229     /// be called. However, all threads will return the same value, produced by
230     /// some `f`.
get_or_init<F>(&self, f: F) -> &'a T where F: FnOnce() -> &'a T,231     pub fn get_or_init<F>(&self, f: F) -> &'a T
232     where
233         F: FnOnce() -> &'a T,
234     {
235         enum Void {}
236         match self.get_or_try_init(|| Ok::<&'a T, Void>(f())) {
237             Ok(val) => val,
238             Err(void) => match void {},
239         }
240     }
241 
242     /// Gets the contents of the cell, initializing it with `f` if
243     /// the cell was empty. If the cell was empty and `f` failed, an
244     /// error is returned.
245     ///
246     /// If several threads concurrently run `get_or_init`, more than one `f` can
247     /// be called. However, all threads will return the same value, produced by
248     /// some `f`.
get_or_try_init<F, E>(&self, f: F) -> Result<&'a T, E> where F: FnOnce() -> Result<&'a T, E>,249     pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&'a T, E>
250     where
251         F: FnOnce() -> Result<&'a T, E>,
252     {
253         let mut ptr = self.inner.load(Ordering::Acquire);
254 
255         if ptr.is_null() {
256             // TODO replace with `cast_mut` when MSRV reaches 1.65.0 (also in `set`)
257             ptr = f()? as *const T as *mut T;
258             let exchange = self.inner.compare_exchange(
259                 ptr::null_mut(),
260                 ptr,
261                 Ordering::AcqRel,
262                 Ordering::Acquire,
263             );
264             if let Err(old) = exchange {
265                 ptr = old;
266             }
267         }
268 
269         Ok(unsafe { &*ptr })
270     }
271 
272     /// ```compile_fail
273     /// use once_cell::race::OnceRef;
274     ///
275     /// let mut l = OnceRef::new();
276     ///
277     /// {
278     ///     let y = 2;
279     ///     let mut r = OnceRef::new();
280     ///     r.set(&y).unwrap();
281     ///     core::mem::swap(&mut l, &mut r);
282     /// }
283     ///
284     /// // l now contains a dangling reference to y
285     /// eprintln!("uaf: {}", l.get().unwrap());
286     /// ```
_dummy()287     fn _dummy() {}
288 }
289 
290 #[cfg(feature = "alloc")]
291 pub use self::once_box::OnceBox;
292 
293 #[cfg(feature = "alloc")]
294 mod once_box {
295     use super::atomic::{AtomicPtr, Ordering};
296     use core::{marker::PhantomData, ptr};
297 
298     use alloc::boxed::Box;
299 
300     /// A thread-safe cell which can be written to only once.
301     pub struct OnceBox<T> {
302         inner: AtomicPtr<T>,
303         ghost: PhantomData<Option<Box<T>>>,
304     }
305 
306     impl<T> core::fmt::Debug for OnceBox<T> {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result307         fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
308             write!(f, "OnceBox({:?})", self.inner.load(Ordering::Relaxed))
309         }
310     }
311 
312     impl<T> Default for OnceBox<T> {
default() -> Self313         fn default() -> Self {
314             Self::new()
315         }
316     }
317 
318     impl<T> Drop for OnceBox<T> {
drop(&mut self)319         fn drop(&mut self) {
320             let ptr = *self.inner.get_mut();
321             if !ptr.is_null() {
322                 drop(unsafe { Box::from_raw(ptr) })
323             }
324         }
325     }
326 
327     impl<T> OnceBox<T> {
328         /// Creates a new empty cell.
new() -> OnceBox<T>329         pub const fn new() -> OnceBox<T> {
330             OnceBox { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData }
331         }
332 
333         /// Gets a reference to the underlying value.
get(&self) -> Option<&T>334         pub fn get(&self) -> Option<&T> {
335             let ptr = self.inner.load(Ordering::Acquire);
336             if ptr.is_null() {
337                 return None;
338             }
339             Some(unsafe { &*ptr })
340         }
341 
342         /// Sets the contents of this cell to `value`.
343         ///
344         /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was
345         /// full.
set(&self, value: Box<T>) -> Result<(), Box<T>>346         pub fn set(&self, value: Box<T>) -> Result<(), Box<T>> {
347             let ptr = Box::into_raw(value);
348             let exchange = self.inner.compare_exchange(
349                 ptr::null_mut(),
350                 ptr,
351                 Ordering::AcqRel,
352                 Ordering::Acquire,
353             );
354             if exchange.is_err() {
355                 let value = unsafe { Box::from_raw(ptr) };
356                 return Err(value);
357             }
358             Ok(())
359         }
360 
361         /// Gets the contents of the cell, initializing it with `f` if the cell was
362         /// empty.
363         ///
364         /// If several threads concurrently run `get_or_init`, more than one `f` can
365         /// be called. However, all threads will return the same value, produced by
366         /// some `f`.
get_or_init<F>(&self, f: F) -> &T where F: FnOnce() -> Box<T>,367         pub fn get_or_init<F>(&self, f: F) -> &T
368         where
369             F: FnOnce() -> Box<T>,
370         {
371             enum Void {}
372             match self.get_or_try_init(|| Ok::<Box<T>, Void>(f())) {
373                 Ok(val) => val,
374                 Err(void) => match void {},
375             }
376         }
377 
378         /// Gets the contents of the cell, initializing it with `f` if
379         /// the cell was empty. If the cell was empty and `f` failed, an
380         /// error is returned.
381         ///
382         /// If several threads concurrently run `get_or_init`, more than one `f` can
383         /// be called. However, all threads will return the same value, produced by
384         /// some `f`.
get_or_try_init<F, E>(&self, f: F) -> Result<&T, E> where F: FnOnce() -> Result<Box<T>, E>,385         pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
386         where
387             F: FnOnce() -> Result<Box<T>, E>,
388         {
389             let mut ptr = self.inner.load(Ordering::Acquire);
390 
391             if ptr.is_null() {
392                 let val = f()?;
393                 ptr = Box::into_raw(val);
394                 let exchange = self.inner.compare_exchange(
395                     ptr::null_mut(),
396                     ptr,
397                     Ordering::AcqRel,
398                     Ordering::Acquire,
399                 );
400                 if let Err(old) = exchange {
401                     drop(unsafe { Box::from_raw(ptr) });
402                     ptr = old;
403                 }
404             };
405             Ok(unsafe { &*ptr })
406         }
407     }
408 
409     unsafe impl<T: Sync + Send> Sync for OnceBox<T> {}
410 
411     /// ```compile_fail
412     /// struct S(*mut ());
413     /// unsafe impl Sync for S {}
414     ///
415     /// fn share<T: Sync>(_: &T) {}
416     /// share(&once_cell::race::OnceBox::<S>::new());
417     /// ```
_dummy()418     fn _dummy() {}
419 }
420