/rust/registry/src/index.crates.io-1949cf8c6b5b557f/once_cell-1.17.0/src/race.rs
Line | Count | Source |
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] |
41 | 0 | pub const fn new() -> OnceNonZeroUsize { |
42 | 0 | OnceNonZeroUsize { inner: AtomicUsize::new(0) } |
43 | 0 | } |
44 | | |
45 | | /// Gets the underlying value. |
46 | | #[inline] |
47 | 0 | pub fn get(&self) -> Option<NonZeroUsize> { |
48 | 0 | let val = self.inner.load(Ordering::Acquire); |
49 | 0 | NonZeroUsize::new(val) |
50 | 0 | } |
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] |
57 | 0 | pub fn set(&self, value: NonZeroUsize) -> Result<(), ()> { |
58 | 0 | let exchange = |
59 | 0 | self.inner.compare_exchange(0, value.get(), Ordering::AcqRel, Ordering::Acquire); |
60 | 0 | match exchange { |
61 | 0 | Ok(_) => Ok(()), |
62 | 0 | Err(_) => Err(()), |
63 | | } |
64 | 0 | } |
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`. |
72 | 0 | pub fn get_or_init<F>(&self, f: F) -> NonZeroUsize |
73 | 0 | where |
74 | 0 | F: FnOnce() -> NonZeroUsize, |
75 | | { |
76 | | enum Void {} |
77 | 0 | match self.get_or_try_init(|| Ok::<NonZeroUsize, Void>(f())) { |
78 | 0 | Ok(val) => val, |
79 | | Err(void) => match void {}, |
80 | | } |
81 | 0 | } |
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`. |
90 | 0 | pub fn get_or_try_init<F, E>(&self, f: F) -> Result<NonZeroUsize, E> |
91 | 0 | where |
92 | 0 | F: FnOnce() -> Result<NonZeroUsize, E>, |
93 | | { |
94 | 0 | let val = self.inner.load(Ordering::Acquire); |
95 | 0 | let res = match NonZeroUsize::new(val) { |
96 | 0 | Some(it) => it, |
97 | | None => { |
98 | 0 | let mut val = f()?.get(); |
99 | 0 | let exchange = |
100 | 0 | self.inner.compare_exchange(0, val, Ordering::AcqRel, Ordering::Acquire); |
101 | 0 | if let Err(old) = exchange { |
102 | 0 | val = old; |
103 | 0 | } |
104 | 0 | unsafe { NonZeroUsize::new_unchecked(val) } |
105 | | } |
106 | | }; |
107 | 0 | Ok(res) |
108 | 0 | } |
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] |
120 | 0 | pub const fn new() -> OnceBool { |
121 | 0 | OnceBool { inner: OnceNonZeroUsize::new() } |
122 | 0 | } |
123 | | |
124 | | /// Gets the underlying value. |
125 | | #[inline] |
126 | 0 | pub fn get(&self) -> Option<bool> { |
127 | 0 | self.inner.get().map(OnceBool::from_usize) |
128 | 0 | } |
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] |
135 | 0 | pub fn set(&self, value: bool) -> Result<(), ()> { |
136 | 0 | self.inner.set(OnceBool::to_usize(value)) |
137 | 0 | } |
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`. |
145 | 0 | pub fn get_or_init<F>(&self, f: F) -> bool |
146 | 0 | where |
147 | 0 | F: FnOnce() -> bool, |
148 | | { |
149 | 0 | OnceBool::from_usize(self.inner.get_or_init(|| OnceBool::to_usize(f()))) |
150 | 0 | } |
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`. |
159 | 0 | pub fn get_or_try_init<F, E>(&self, f: F) -> Result<bool, E> |
160 | 0 | where |
161 | 0 | F: FnOnce() -> Result<bool, E>, |
162 | | { |
163 | 0 | self.inner.get_or_try_init(|| f().map(OnceBool::to_usize)).map(OnceBool::from_usize) |
164 | 0 | } |
165 | | |
166 | | #[inline] |
167 | 0 | fn from_usize(value: NonZeroUsize) -> bool { |
168 | 0 | value.get() == 1 |
169 | 0 | } |
170 | | |
171 | | #[inline] |
172 | 0 | fn to_usize(value: bool) -> NonZeroUsize { |
173 | 0 | unsafe { NonZeroUsize::new_unchecked(if value { 1 } else { 2 }) } |
174 | 0 | } |
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> { |
187 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
188 | 0 | write!(f, "OnceRef({:?})", self.inner) |
189 | 0 | } |
190 | | } |
191 | | |
192 | | impl<'a, T> Default for OnceRef<'a, T> { |
193 | 0 | fn default() -> Self { |
194 | 0 | Self::new() |
195 | 0 | } |
196 | | } |
197 | | |
198 | | impl<'a, T> OnceRef<'a, T> { |
199 | | /// Creates a new empty cell. |
200 | 0 | pub const fn new() -> OnceRef<'a, T> { |
201 | 0 | OnceRef { inner: OnceNonZeroUsize::new(), ghost: PhantomData } |
202 | 0 | } |
203 | | |
204 | | /// Gets a reference to the underlying value. |
205 | 0 | pub fn get(&self) -> Option<&'a T> { |
206 | 0 | self.inner.get().map(|ptr| unsafe { &*(ptr.get() as *const T) }) |
207 | 0 | } |
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. |
213 | 0 | pub fn set(&self, value: &'a T) -> Result<(), ()> { |
214 | 0 | let ptr = NonZeroUsize::new(value as *const T as usize).unwrap(); |
215 | 0 | self.inner.set(ptr) |
216 | 0 | } |
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`. |
224 | 0 | pub fn get_or_init<F>(&self, f: F) -> &'a T |
225 | 0 | where |
226 | 0 | F: FnOnce() -> &'a T, |
227 | | { |
228 | 0 | let f = || NonZeroUsize::new(f() as *const T as usize).unwrap(); |
229 | 0 | let ptr = self.inner.get_or_init(f); |
230 | 0 | unsafe { &*(ptr.get() as *const T) } |
231 | 0 | } |
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`. |
240 | 0 | pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&'a T, E> |
241 | 0 | where |
242 | 0 | F: FnOnce() -> Result<&'a T, E>, |
243 | | { |
244 | 0 | let f = || f().map(|value| NonZeroUsize::new(value as *const T as usize).unwrap()); |
245 | 0 | let ptr = self.inner.get_or_try_init(f)?; |
246 | 0 | unsafe { Ok(&*(ptr.get() as *const T)) } |
247 | 0 | } |
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 | | /// ``` |
264 | 0 | 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> { |
284 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
285 | 0 | write!(f, "OnceBox({:?})", self.inner.load(Ordering::Relaxed)) |
286 | 0 | } |
287 | | } |
288 | | |
289 | | impl<T> Default for OnceBox<T> { |
290 | 0 | fn default() -> Self { |
291 | 0 | Self::new() |
292 | 0 | } |
293 | | } |
294 | | |
295 | | impl<T> Drop for OnceBox<T> { |
296 | 0 | fn drop(&mut self) { |
297 | 0 | let ptr = *self.inner.get_mut(); |
298 | 0 | if !ptr.is_null() { |
299 | 0 | drop(unsafe { Box::from_raw(ptr) }) |
300 | 0 | } |
301 | 0 | } |
302 | | } |
303 | | |
304 | | impl<T> OnceBox<T> { |
305 | | /// Creates a new empty cell. |
306 | 0 | pub const fn new() -> OnceBox<T> { |
307 | 0 | OnceBox { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData } |
308 | 0 | } |
309 | | |
310 | | /// Gets a reference to the underlying value. |
311 | 0 | pub fn get(&self) -> Option<&T> { |
312 | 0 | let ptr = self.inner.load(Ordering::Acquire); |
313 | 0 | if ptr.is_null() { |
314 | 0 | return None; |
315 | 0 | } |
316 | 0 | Some(unsafe { &*ptr }) |
317 | 0 | } |
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. |
323 | 0 | pub fn set(&self, value: Box<T>) -> Result<(), Box<T>> { |
324 | 0 | let ptr = Box::into_raw(value); |
325 | 0 | let exchange = self.inner.compare_exchange( |
326 | 0 | ptr::null_mut(), |
327 | 0 | ptr, |
328 | 0 | Ordering::AcqRel, |
329 | 0 | Ordering::Acquire, |
330 | | ); |
331 | 0 | if let Err(_) = exchange { |
332 | 0 | let value = unsafe { Box::from_raw(ptr) }; |
333 | 0 | return Err(value); |
334 | 0 | } |
335 | 0 | Ok(()) |
336 | 0 | } |
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`. |
344 | 0 | pub fn get_or_init<F>(&self, f: F) -> &T |
345 | 0 | where |
346 | 0 | F: FnOnce() -> Box<T>, |
347 | | { |
348 | | enum Void {} |
349 | 0 | match self.get_or_try_init(|| Ok::<Box<T>, Void>(f())) { |
350 | 0 | Ok(val) => val, |
351 | | Err(void) => match void {}, |
352 | | } |
353 | 0 | } |
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`. |
362 | 0 | pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E> |
363 | 0 | where |
364 | 0 | F: FnOnce() -> Result<Box<T>, E>, |
365 | | { |
366 | 0 | let mut ptr = self.inner.load(Ordering::Acquire); |
367 | | |
368 | 0 | if ptr.is_null() { |
369 | 0 | let val = f()?; |
370 | 0 | ptr = Box::into_raw(val); |
371 | 0 | let exchange = self.inner.compare_exchange( |
372 | 0 | ptr::null_mut(), |
373 | 0 | ptr, |
374 | 0 | Ordering::AcqRel, |
375 | 0 | Ordering::Acquire, |
376 | | ); |
377 | 0 | if let Err(old) = exchange { |
378 | 0 | drop(unsafe { Box::from_raw(ptr) }); |
379 | 0 | ptr = old; |
380 | 0 | } |
381 | 0 | }; |
382 | 0 | Ok(unsafe { &*ptr }) |
383 | 0 | } |
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 | | /// ``` |
395 | 0 | fn _dummy() {} |
396 | | } |