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