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