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}