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