/rust/registry/src/index.crates.io-1949cf8c6b5b557f/spin-0.9.9/src/once.rs
Line | Count | Source |
1 | | //! Synchronization primitives for one-time evaluation. |
2 | | |
3 | | use crate::{ |
4 | | atomic::{AtomicU8, Ordering}, |
5 | | RelaxStrategy, Spin, |
6 | | }; |
7 | | use core::{ |
8 | | cell::UnsafeCell, |
9 | | fmt, |
10 | | marker::PhantomData, |
11 | | mem::{ManuallyDrop, MaybeUninit}, |
12 | | }; |
13 | | |
14 | | /// A primitive that provides lazy one-time initialization. |
15 | | /// |
16 | | /// Unlike its `std::sync` equivalent, this is generalized such that the closure returns a |
17 | | /// value to be stored by the [`Once`] (`std::sync::Once` can be trivially emulated with |
18 | | /// `Once`). |
19 | | /// |
20 | | /// Because [`Once::new`] is `const`, this primitive may be used to safely initialize statics. |
21 | | /// |
22 | | /// # Examples |
23 | | /// |
24 | | /// ``` |
25 | | /// use spin; |
26 | | /// |
27 | | /// static START: spin::Once = spin::Once::new(); |
28 | | /// |
29 | | /// START.call_once(|| { |
30 | | /// // run initialization here |
31 | | /// }); |
32 | | /// ``` |
33 | | pub struct Once<T = (), R = Spin> { |
34 | | phantom: PhantomData<R>, |
35 | | status: AtomicStatus, |
36 | | data: UnsafeCell<MaybeUninit<T>>, |
37 | | } |
38 | | |
39 | | impl<T, R> Default for Once<T, R> { |
40 | 0 | fn default() -> Self { |
41 | 0 | Self::new() |
42 | 0 | } |
43 | | } |
44 | | |
45 | | impl<T: fmt::Debug, R> fmt::Debug for Once<T, R> { |
46 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
47 | 0 | match self.get() { |
48 | 0 | Some(s) => write!(f, "Once {{ data: ") |
49 | 0 | .and_then(|()| s.fmt(f)) |
50 | 0 | .and_then(|()| write!(f, "}}")), |
51 | 0 | None => write!(f, "Once {{ <uninitialized> }}"), |
52 | | } |
53 | 0 | } |
54 | | } |
55 | | |
56 | | // Same unsafe impls as `std::sync::RwLock`, because this also allows for |
57 | | // concurrent reads. |
58 | | unsafe impl<T: Send + Sync, R> Sync for Once<T, R> {} |
59 | | unsafe impl<T: Send, R> Send for Once<T, R> {} |
60 | | |
61 | | mod status { |
62 | | use super::*; |
63 | | |
64 | | // SAFETY: This structure has an invariant, namely that the inner atomic u8 must *always* have |
65 | | // a value for which there exists a valid Status. This means that users of this API must only |
66 | | // be allowed to load and store `Status`es. |
67 | | #[repr(transparent)] |
68 | | pub struct AtomicStatus(AtomicU8); |
69 | | |
70 | | // Four states that a Once can be in, encoded into the lower bits of `status` in |
71 | | // the Once structure. |
72 | | #[repr(u8)] |
73 | | #[derive(Clone, Copy, Debug, PartialEq)] |
74 | | pub enum Status { |
75 | | Incomplete = 0x00, |
76 | | Running = 0x01, |
77 | | Complete = 0x02, |
78 | | Panicked = 0x03, |
79 | | } |
80 | | impl Status { |
81 | | // Construct a status from an inner u8 integer. |
82 | | // |
83 | | // # Safety |
84 | | // |
85 | | // For this to be safe, the inner number must have a valid corresponding enum variant. |
86 | 0 | unsafe fn new_unchecked(inner: u8) -> Self { |
87 | 0 | core::mem::transmute(inner) |
88 | 0 | } |
89 | | } |
90 | | |
91 | | impl AtomicStatus { |
92 | | #[inline(always)] |
93 | 0 | pub const fn new(status: Status) -> Self { |
94 | | // SAFETY: We got the value directly from status, so transmuting back is fine. |
95 | 0 | Self(AtomicU8::new(status as u8)) |
96 | 0 | } |
97 | | #[inline(always)] |
98 | 0 | pub fn load(&self, ordering: Ordering) -> Status { |
99 | | // SAFETY: We know that the inner integer must have been constructed from a Status in |
100 | | // the first place. |
101 | 0 | unsafe { Status::new_unchecked(self.0.load(ordering)) } |
102 | 0 | } |
103 | | #[inline(always)] |
104 | 0 | pub fn store(&self, status: Status, ordering: Ordering) { |
105 | | // SAFETY: While not directly unsafe, this is safe because the value was retrieved from |
106 | | // a status, thus making transmutation safe. |
107 | 0 | self.0.store(status as u8, ordering); |
108 | 0 | } |
109 | | #[inline(always)] |
110 | 0 | pub fn compare_exchange( |
111 | 0 | &self, |
112 | 0 | old: Status, |
113 | 0 | new: Status, |
114 | 0 | success: Ordering, |
115 | 0 | failure: Ordering, |
116 | 0 | ) -> Result<Status, Status> { |
117 | 0 | match self |
118 | 0 | .0 |
119 | 0 | .compare_exchange(old as u8, new as u8, success, failure) |
120 | | { |
121 | | // SAFETY: A compare exchange will always return a value that was later stored into |
122 | | // the atomic u8, but due to the invariant that it must be a valid Status, we know |
123 | | // that both Ok(_) and Err(_) will be safely transmutable. |
124 | 0 | Ok(ok) => Ok(unsafe { Status::new_unchecked(ok) }), |
125 | 0 | Err(err) => Err(unsafe { Status::new_unchecked(err) }), |
126 | | } |
127 | 0 | } |
128 | | #[inline(always)] |
129 | 0 | pub fn get_mut(&mut self) -> &mut Status { |
130 | | // SAFETY: Since we know that the u8 inside must be a valid Status, we can safely cast |
131 | | // it to a &mut Status. |
132 | 0 | unsafe { &mut *((self.0.get_mut() as *mut u8).cast::<Status>()) } |
133 | 0 | } |
134 | | } |
135 | | } |
136 | | use self::status::{AtomicStatus, Status}; |
137 | | |
138 | | impl<T, R: RelaxStrategy> Once<T, R> { |
139 | | /// Performs an initialization routine once and only once. The given closure |
140 | | /// will be executed if this is the first time `call_once` has been called, |
141 | | /// and otherwise the routine will *not* be invoked. |
142 | | /// |
143 | | /// This method will block the calling thread if another initialization |
144 | | /// routine is currently running. |
145 | | /// |
146 | | /// When this function returns, it is guaranteed that some initialization |
147 | | /// has run and completed (it may not be the closure specified). The |
148 | | /// returned pointer will point to the result from the closure that was |
149 | | /// run. |
150 | | /// |
151 | | /// # Panics |
152 | | /// |
153 | | /// This function will panic if the [`Once`] previously panicked while attempting |
154 | | /// to initialize. This is similar to the poisoning behaviour of `std::sync`'s |
155 | | /// primitives. |
156 | | /// |
157 | | /// # Examples |
158 | | /// |
159 | | /// ``` |
160 | | /// use spin; |
161 | | /// |
162 | | /// static INIT: spin::Once<usize> = spin::Once::new(); |
163 | | /// |
164 | | /// fn get_cached_val() -> usize { |
165 | | /// *INIT.call_once(expensive_computation) |
166 | | /// } |
167 | | /// |
168 | | /// fn expensive_computation() -> usize { |
169 | | /// // ... |
170 | | /// # 2 |
171 | | /// } |
172 | | /// ``` |
173 | 0 | pub fn call_once<F: FnOnce() -> T>(&self, f: F) -> &T { |
174 | 0 | match self.try_call_once(|| Ok::<T, core::convert::Infallible>(f())) {Unexecuted instantiation: <spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>>>::call_once::<<flexi_logger::deferred_now::FORCE_UTC as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>>>::call_once::<<flexi_logger::util::ERROR_CHANNEL as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>>>::call_once::<<flexi_logger::formats::PALETTE as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}Unexecuted instantiation: <spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>>::call_once::<<spdmlib::crypto::spdm_ring::hash_impl::hash_ext::HASH_CTX_TABLE as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}Unexecuted instantiation: <spin::once::Once<_, _>>::call_once::<_>::{closure#0} |
175 | 0 | Ok(x) => x, |
176 | | Err(void) => match void {}, |
177 | | } |
178 | 0 | } Unexecuted instantiation: <spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>>>::call_once::<<flexi_logger::deferred_now::FORCE_UTC as core::ops::deref::Deref>::deref::__static_ref_initialize> Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>>>::call_once::<<flexi_logger::util::ERROR_CHANNEL as core::ops::deref::Deref>::deref::__static_ref_initialize> Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>>>::call_once::<<flexi_logger::formats::PALETTE as core::ops::deref::Deref>::deref::__static_ref_initialize> Unexecuted instantiation: <spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>>::call_once::<<spdmlib::crypto::spdm_ring::hash_impl::hash_ext::HASH_CTX_TABLE as core::ops::deref::Deref>::deref::__static_ref_initialize> Unexecuted instantiation: <spin::once::Once<_, _>>::call_once::<_> |
179 | | |
180 | | /// This method is similar to `call_once`, but allows the given closure to |
181 | | /// fail, and lets the `Once` in a uninitialized state if it does. |
182 | | /// |
183 | | /// This method will block the calling thread if another initialization |
184 | | /// routine is currently running. |
185 | | /// |
186 | | /// When this function returns without error, it is guaranteed that some |
187 | | /// initialization has run and completed (it may not be the closure |
188 | | /// specified). The returned reference will point to the result from the |
189 | | /// closure that was run. |
190 | | /// |
191 | | /// # Panics |
192 | | /// |
193 | | /// This function will panic if the [`Once`] previously panicked while attempting |
194 | | /// to initialize. This is similar to the poisoning behaviour of `std::sync`'s |
195 | | /// primitives. |
196 | | /// |
197 | | /// # Examples |
198 | | /// |
199 | | /// ``` |
200 | | /// use spin; |
201 | | /// |
202 | | /// static INIT: spin::Once<usize> = spin::Once::new(); |
203 | | /// |
204 | | /// fn get_cached_val() -> Result<usize, String> { |
205 | | /// INIT.try_call_once(expensive_fallible_computation).map(|x| *x) |
206 | | /// } |
207 | | /// |
208 | | /// fn expensive_fallible_computation() -> Result<usize, String> { |
209 | | /// // ... |
210 | | /// # Ok(2) |
211 | | /// } |
212 | | /// ``` |
213 | 0 | pub fn try_call_once<F: FnOnce() -> Result<T, E>, E>(&self, f: F) -> Result<&T, E> { |
214 | 0 | if let Some(value) = self.get() { |
215 | 0 | Ok(value) |
216 | | } else { |
217 | 0 | self.try_call_once_slow(f) |
218 | | } |
219 | 0 | } Unexecuted instantiation: <spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>>>::try_call_once::<<spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>>>::call_once<<flexi_logger::deferred_now::FORCE_UTC as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}, core::convert::Infallible>Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>>>::try_call_once::<<spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>>>::call_once<<flexi_logger::util::ERROR_CHANNEL as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}, core::convert::Infallible>Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>>>::try_call_once::<<spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>>>::call_once<<flexi_logger::formats::PALETTE as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}, core::convert::Infallible>Unexecuted instantiation: <spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>>::try_call_once::<<spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>>::call_once<<spdmlib::crypto::spdm_ring::hash_impl::hash_ext::HASH_CTX_TABLE as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}, core::convert::Infallible>Unexecuted instantiation: <spin::once::Once<_, _>>::try_call_once::<_, _> |
220 | | |
221 | | #[cold] |
222 | 0 | fn try_call_once_slow<F: FnOnce() -> Result<T, E>, E>(&self, f: F) -> Result<&T, E> { |
223 | | loop { |
224 | 0 | let xchg = self.status.compare_exchange( |
225 | 0 | Status::Incomplete, |
226 | 0 | Status::Running, |
227 | 0 | Ordering::Acquire, |
228 | 0 | Ordering::Acquire, |
229 | | ); |
230 | | |
231 | 0 | match xchg { |
232 | 0 | Ok(_must_be_state_incomplete) => { |
233 | 0 | // Impl is defined after the match for readability |
234 | 0 | } |
235 | 0 | Err(Status::Panicked) => panic!("Once panicked"), |
236 | 0 | Err(Status::Running) => match self.poll() { |
237 | 0 | Some(v) => return Ok(v), |
238 | 0 | None => continue, |
239 | | }, |
240 | | Err(Status::Complete) => { |
241 | 0 | return Ok(unsafe { |
242 | 0 | // SAFETY: The status is Complete |
243 | 0 | self.force_get() |
244 | 0 | }); |
245 | | } |
246 | | Err(Status::Incomplete) => { |
247 | | // The compare_exchange failed, so this shouldn't ever be reached, |
248 | | // however if we decide to switch to compare_exchange_weak it will |
249 | | // be safer to leave this here than hit an unreachable |
250 | 0 | continue; |
251 | | } |
252 | | } |
253 | | |
254 | | // The compare-exchange succeeded, so we shall initialize it. |
255 | | |
256 | | // We use a guard (Finish) to catch panics caused by builder |
257 | 0 | let finish = Finish { |
258 | 0 | status: &self.status, |
259 | 0 | }; |
260 | 0 | let val = match f() { |
261 | 0 | Ok(val) => val, |
262 | 0 | Err(err) => { |
263 | | // If an error occurs, clean up everything and leave. |
264 | 0 | core::mem::forget(finish); |
265 | 0 | self.status.store(Status::Incomplete, Ordering::Release); |
266 | 0 | return Err(err); |
267 | | } |
268 | | }; |
269 | 0 | unsafe { |
270 | 0 | // SAFETY: |
271 | 0 | // `UnsafeCell`/deref: currently the only accessor, mutably |
272 | 0 | // and immutably by cas exclusion. |
273 | 0 | // `write`: pointer comes from `MaybeUninit`. |
274 | 0 | (*self.data.get()).as_mut_ptr().write(val); |
275 | 0 | }; |
276 | | // If there were to be a panic with unwind enabled, the code would |
277 | | // short-circuit and never reach the point where it writes the inner data. |
278 | | // The destructor for Finish will run, and poison the Once to ensure that other |
279 | | // threads accessing it do not exhibit unwanted behavior, if there were to be |
280 | | // any inconsistency in data structures caused by the panicking thread. |
281 | | // |
282 | | // However, f() is expected in the general case not to panic. In that case, we |
283 | | // simply forget the guard, bypassing its destructor. We could theoretically |
284 | | // clear a flag instead, but this eliminates the call to the destructor at |
285 | | // compile time, and unconditionally poisons during an eventual panic, if |
286 | | // unwinding is enabled. |
287 | 0 | core::mem::forget(finish); |
288 | | |
289 | | // SAFETY: Release is required here, so that all memory accesses done in the |
290 | | // closure when initializing, become visible to other threads that perform Acquire |
291 | | // loads. |
292 | | // |
293 | | // And, we also know that the changes this thread has done will not magically |
294 | | // disappear from our cache, so it does not need to be AcqRel. |
295 | 0 | self.status.store(Status::Complete, Ordering::Release); |
296 | | |
297 | | // This next line is mainly an optimization. |
298 | 0 | return unsafe { Ok(self.force_get()) }; |
299 | | } |
300 | 0 | } Unexecuted instantiation: <spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>>>::try_call_once_slow::<<spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>>>::call_once<<flexi_logger::deferred_now::FORCE_UTC as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}, core::convert::Infallible>Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>>>::try_call_once_slow::<<spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>>>::call_once<<flexi_logger::util::ERROR_CHANNEL as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}, core::convert::Infallible>Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>>>::try_call_once_slow::<<spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>>>::call_once<<flexi_logger::formats::PALETTE as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}, core::convert::Infallible>Unexecuted instantiation: <spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>>::try_call_once_slow::<<spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>>::call_once<<spdmlib::crypto::spdm_ring::hash_impl::hash_ext::HASH_CTX_TABLE as core::ops::deref::Deref>::deref::__static_ref_initialize>::{closure#0}, core::convert::Infallible>Unexecuted instantiation: <spin::once::Once<_, _>>::try_call_once_slow::<_, _> |
301 | | |
302 | | /// Spins until the [`Once`] contains a value. |
303 | | /// |
304 | | /// Note that in releases prior to `0.7`, this function had the behaviour of [`Once::poll`]. |
305 | | /// |
306 | | /// # Panics |
307 | | /// |
308 | | /// This function will panic if the [`Once`] previously panicked while attempting |
309 | | /// to initialize. This is similar to the poisoning behaviour of `std::sync`'s |
310 | | /// primitives. |
311 | 0 | pub fn wait(&self) -> &T { |
312 | | loop { |
313 | 0 | match self.poll() { |
314 | 0 | Some(x) => break x, |
315 | 0 | None => R::relax(), |
316 | | } |
317 | | } |
318 | 0 | } |
319 | | |
320 | | /// Like [`Once::get`], but will spin if the [`Once`] is in the process of being |
321 | | /// initialized. If initialization has not even begun, `None` will be returned. |
322 | | /// |
323 | | /// Note that in releases prior to `0.7`, this function was named `wait`. |
324 | | /// |
325 | | /// # Panics |
326 | | /// |
327 | | /// This function will panic if the [`Once`] previously panicked while attempting |
328 | | /// to initialize. This is similar to the poisoning behaviour of `std::sync`'s |
329 | | /// primitives. |
330 | 0 | pub fn poll(&self) -> Option<&T> { |
331 | | loop { |
332 | | // SAFETY: Acquire is safe here, because if the status is COMPLETE, then we want to make |
333 | | // sure that all memory accessed done while initializing that value, are visible when |
334 | | // we return a reference to the inner data after this load. |
335 | 0 | match self.status.load(Ordering::Acquire) { |
336 | 0 | Status::Incomplete => return None, |
337 | 0 | Status::Running => R::relax(), // We spin |
338 | 0 | Status::Complete => return Some(unsafe { self.force_get() }), |
339 | 0 | Status::Panicked => panic!("Once previously poisoned by a panicked"), |
340 | | } |
341 | | } |
342 | 0 | } Unexecuted instantiation: <spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>>>::poll Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>>>::poll Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>>>::poll Unexecuted instantiation: <spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>>::poll Unexecuted instantiation: <spin::once::Once<_, _>>::poll |
343 | | } |
344 | | |
345 | | impl<T, R> Once<T, R> { |
346 | | /// Initialization constant of [`Once`]. |
347 | | #[allow(clippy::declare_interior_mutable_const)] |
348 | | pub const INIT: Self = Self { |
349 | | phantom: PhantomData, |
350 | | status: AtomicStatus::new(Status::Incomplete), |
351 | | data: UnsafeCell::new(MaybeUninit::uninit()), |
352 | | }; |
353 | | |
354 | | /// Creates a new [`Once`]. |
355 | 0 | pub const fn new() -> Self { |
356 | 0 | Self::INIT |
357 | 0 | } |
358 | | |
359 | | /// Creates a new initialized [`Once`]. |
360 | 0 | pub const fn initialized(data: T) -> Self { |
361 | 0 | Self { |
362 | 0 | phantom: PhantomData, |
363 | 0 | status: AtomicStatus::new(Status::Complete), |
364 | 0 | data: UnsafeCell::new(MaybeUninit::new(data)), |
365 | 0 | } |
366 | 0 | } |
367 | | |
368 | | /// Retrieve a pointer to the inner data. |
369 | | /// |
370 | | /// While this method itself is safe, accessing the pointer before the [`Once`] has been |
371 | | /// initialized is UB, unless this method has already been written to from a pointer coming |
372 | | /// from this method. |
373 | 0 | pub fn as_mut_ptr(&self) -> *mut T { |
374 | | // SAFETY: |
375 | | // * MaybeUninit<T> always has exactly the same layout as T |
376 | 0 | self.data.get().cast::<T>() |
377 | 0 | } |
378 | | |
379 | | /// Get a reference to the initialized instance. Must only be called once COMPLETE. |
380 | 0 | unsafe fn force_get(&self) -> &T { |
381 | | // SAFETY: |
382 | | // * `UnsafeCell`/inner deref: data never changes again |
383 | | // * `MaybeUninit`/outer deref: data was initialized |
384 | 0 | &*(*self.data.get()).as_ptr() |
385 | 0 | } Unexecuted instantiation: <spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>>>::force_get Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>>>::force_get Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>>>::force_get Unexecuted instantiation: <spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>>::force_get Unexecuted instantiation: <spin::once::Once<_, _>>::force_get |
386 | | |
387 | | /// Get a reference to the initialized instance. Must only be called once COMPLETE. |
388 | 0 | unsafe fn force_get_mut(&mut self) -> &mut T { |
389 | | // SAFETY: |
390 | | // * `UnsafeCell`/inner deref: data never changes again |
391 | | // * `MaybeUninit`/outer deref: data was initialized |
392 | 0 | &mut *(*self.data.get()).as_mut_ptr() |
393 | 0 | } |
394 | | |
395 | | /// Get a reference to the initialized instance. Must only be called once COMPLETE. |
396 | 0 | unsafe fn force_into_inner(self) -> T { |
397 | 0 | let mut this = ManuallyDrop::new(self); |
398 | | // SAFETY: |
399 | | // * `UnsafeCell`/inner deref: data never changes again |
400 | | // * `MaybeUninit`/outer deref: data was initialized |
401 | | // * We never call `self`'s destructor, ensuring a double-drop cannot occur. |
402 | 0 | this.data.get_mut().assume_init_read() |
403 | 0 | } |
404 | | |
405 | | /// Returns a reference to the inner value if the [`Once`] has been initialized. |
406 | 0 | pub fn get(&self) -> Option<&T> { |
407 | | // SAFETY: Just as with `poll`, Acquire is safe here because we want to be able to see the |
408 | | // nonatomic stores done when initializing, once we have loaded and checked the status. |
409 | 0 | match self.status.load(Ordering::Acquire) { |
410 | 0 | Status::Complete => Some(unsafe { self.force_get() }), |
411 | 0 | _ => None, |
412 | | } |
413 | 0 | } Unexecuted instantiation: <spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>>>::get Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>>>::get Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>>>::get Unexecuted instantiation: <spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>>::get Unexecuted instantiation: <spin::once::Once<_, _>>::get |
414 | | |
415 | | /// Returns a reference to the inner value on the unchecked assumption that the [`Once`] has been initialized. |
416 | | /// |
417 | | /// # Safety |
418 | | /// |
419 | | /// This is *extremely* unsafe if the `Once` has not already been initialized because a reference to uninitialized |
420 | | /// memory will be returned, immediately triggering undefined behaviour (even if the reference goes unused). |
421 | | /// However, this can be useful in some instances for exposing the `Once` to FFI or when the overhead of atomically |
422 | | /// checking initialization is unacceptable and the `Once` has already been initialized. |
423 | 0 | pub unsafe fn get_unchecked(&self) -> &T { |
424 | 0 | debug_assert_eq!( |
425 | 0 | self.status.load(Ordering::SeqCst), |
426 | | Status::Complete, |
427 | 0 | "Attempted to access an uninitialized Once. If this was run without debug checks, this would be undefined behaviour. This is a serious bug and you must fix it.", |
428 | | ); |
429 | 0 | self.force_get() |
430 | 0 | } |
431 | | |
432 | | /// Returns a mutable reference to the inner value if the [`Once`] has been initialized. |
433 | | /// |
434 | | /// Because this method requires a mutable reference to the [`Once`], no synchronization |
435 | | /// overhead is required to access the inner value. In effect, it is zero-cost. |
436 | 0 | pub fn get_mut(&mut self) -> Option<&mut T> { |
437 | 0 | match *self.status.get_mut() { |
438 | 0 | Status::Complete => Some(unsafe { self.force_get_mut() }), |
439 | 0 | _ => None, |
440 | | } |
441 | 0 | } |
442 | | |
443 | | /// Returns a mutable reference to the inner value |
444 | | /// |
445 | | /// # Safety |
446 | | /// |
447 | | /// This is *extremely* unsafe if the `Once` has not already been initialized because a reference to uninitialized |
448 | | /// memory will be returned, immediately triggering undefined behaviour (even if the reference goes unused). |
449 | | /// However, this can be useful in some instances for exposing the `Once` to FFI or when the overhead of atomically |
450 | | /// checking initialization is unacceptable and the `Once` has already been initialized. |
451 | 0 | pub unsafe fn get_mut_unchecked(&mut self) -> &mut T { |
452 | 0 | debug_assert_eq!( |
453 | 0 | self.status.load(Ordering::SeqCst), |
454 | | Status::Complete, |
455 | 0 | "Attempted to access an unintialized Once. If this was to run without debug checks, this would be undefined behavior. This is a serious bug and you must fix it.", |
456 | | ); |
457 | 0 | self.force_get_mut() |
458 | 0 | } |
459 | | |
460 | | /// Returns a the inner value if the [`Once`] has been initialized. |
461 | | /// |
462 | | /// Because this method requires ownership of the [`Once`], no synchronization overhead |
463 | | /// is required to access the inner value. In effect, it is zero-cost. |
464 | 0 | pub fn try_into_inner(mut self) -> Option<T> { |
465 | 0 | match *self.status.get_mut() { |
466 | 0 | Status::Complete => Some(unsafe { self.force_into_inner() }), |
467 | 0 | _ => None, |
468 | | } |
469 | 0 | } |
470 | | |
471 | | /// Returns a the inner value if the [`Once`] has been initialized. |
472 | | /// # Safety |
473 | | /// |
474 | | /// This is *extremely* unsafe if the `Once` has not already been initialized because a reference to uninitialized |
475 | | /// memory will be returned, immediately triggering undefined behaviour (even if the reference goes unused) |
476 | | /// This can be useful, if `Once` has already been initialized, and you want to bypass an |
477 | | /// option check. |
478 | 0 | pub unsafe fn into_inner_unchecked(self) -> T { |
479 | 0 | debug_assert_eq!( |
480 | 0 | self.status.load(Ordering::SeqCst), |
481 | | Status::Complete, |
482 | 0 | "Attempted to access an unintialized Once. If this was to run without debug checks, this would be undefined behavior. This is a serious bug and you must fix it.", |
483 | | ); |
484 | 0 | self.force_into_inner() |
485 | 0 | } |
486 | | |
487 | | /// Checks whether the value has been initialized. |
488 | | /// |
489 | | /// This is done using [`Acquire`](core::sync::atomic::Ordering::Acquire) ordering, and |
490 | | /// therefore it is safe to access the value directly via |
491 | | /// [`get_unchecked`](Self::get_unchecked) if this returns true. |
492 | 0 | pub fn is_completed(&self) -> bool { |
493 | | // TODO: Add a similar variant for Relaxed? |
494 | 0 | self.status.load(Ordering::Acquire) == Status::Complete |
495 | 0 | } |
496 | | } |
497 | | |
498 | | impl<T, R> From<T> for Once<T, R> { |
499 | 0 | fn from(data: T) -> Self { |
500 | 0 | Self::initialized(data) |
501 | 0 | } |
502 | | } |
503 | | |
504 | | impl<T, R> Drop for Once<T, R> { |
505 | 0 | fn drop(&mut self) { |
506 | | // No need to do any atomic access here, we have &mut! |
507 | 0 | if *self.status.get_mut() == Status::Complete { |
508 | 0 | unsafe { |
509 | 0 | //TODO: Use MaybeUninit::assume_init_drop once stabilised |
510 | 0 | core::ptr::drop_in_place((*self.data.get()).as_mut_ptr()); |
511 | 0 | } |
512 | 0 | } |
513 | 0 | } Unexecuted instantiation: <spin::once::Once<alloc::sync::Arc<std::sync::poison::mutex::Mutex<core::option::Option<bool>>>> as core::ops::drop::Drop>::drop Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::logger::ErrorChannel>> as core::ops::drop::Drop>::drop Unexecuted instantiation: <spin::once::Once<std::sync::poison::rwlock::RwLock<flexi_logger::formats::Palette>> as core::ops::drop::Drop>::drop Unexecuted instantiation: <spin::once::Once<spin::mutex::Mutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>> as core::ops::drop::Drop>::drop Unexecuted instantiation: <spin::once::Once<_, _> as core::ops::drop::Drop>::drop |
514 | | } |
515 | | |
516 | | struct Finish<'a> { |
517 | | status: &'a AtomicStatus, |
518 | | } |
519 | | |
520 | | impl<'a> Drop for Finish<'a> { |
521 | 0 | fn drop(&mut self) { |
522 | | // While using Relaxed here would most likely not be an issue, we use SeqCst anyway. |
523 | | // This is mainly because panics are not meant to be fast at all, but also because if |
524 | | // there were to be a compiler bug which reorders accesses within the same thread, |
525 | | // where it should not, we want to be sure that the panic really is handled, and does |
526 | | // not cause additional problems. SeqCst will therefore help guarding against such |
527 | | // bugs. |
528 | 0 | self.status.store(Status::Panicked, Ordering::SeqCst); |
529 | 0 | } |
530 | | } |
531 | | |
532 | | #[cfg(test)] |
533 | | mod tests { |
534 | | use std::prelude::v1::*; |
535 | | |
536 | | use std::sync::atomic::AtomicU32; |
537 | | use std::sync::mpsc::channel; |
538 | | use std::sync::Arc; |
539 | | use std::thread; |
540 | | |
541 | | use super::*; |
542 | | |
543 | | #[test] |
544 | | fn smoke_once() { |
545 | | static O: Once = Once::new(); |
546 | | let mut a = 0; |
547 | | O.call_once(|| a += 1); |
548 | | assert_eq!(a, 1); |
549 | | O.call_once(|| a += 1); |
550 | | assert_eq!(a, 1); |
551 | | } |
552 | | |
553 | | #[test] |
554 | | fn smoke_once_value() { |
555 | | static O: Once<usize> = Once::new(); |
556 | | let a = O.call_once(|| 1); |
557 | | assert_eq!(*a, 1); |
558 | | let b = O.call_once(|| 2); |
559 | | assert_eq!(*b, 1); |
560 | | } |
561 | | |
562 | | #[test] |
563 | | fn stampede_once() { |
564 | | static O: Once = Once::new(); |
565 | | static mut RUN: bool = false; |
566 | | |
567 | | let (tx, rx) = channel(); |
568 | | let mut ts = Vec::new(); |
569 | | for _ in 0..10 { |
570 | | let tx = tx.clone(); |
571 | | ts.push(thread::spawn(move || { |
572 | | for _ in 0..4 { |
573 | | thread::yield_now() |
574 | | } |
575 | | unsafe { |
576 | | O.call_once(|| { |
577 | | assert!(!RUN); |
578 | | RUN = true; |
579 | | }); |
580 | | assert!(RUN); |
581 | | } |
582 | | tx.send(()).unwrap(); |
583 | | })); |
584 | | } |
585 | | |
586 | | unsafe { |
587 | | O.call_once(|| { |
588 | | assert!(!RUN); |
589 | | RUN = true; |
590 | | }); |
591 | | assert!(RUN); |
592 | | } |
593 | | |
594 | | for _ in 0..10 { |
595 | | rx.recv().unwrap(); |
596 | | } |
597 | | |
598 | | for t in ts { |
599 | | t.join().unwrap(); |
600 | | } |
601 | | } |
602 | | |
603 | | #[test] |
604 | | fn get() { |
605 | | static INIT: Once<usize> = Once::new(); |
606 | | |
607 | | assert!(INIT.get().is_none()); |
608 | | INIT.call_once(|| 2); |
609 | | assert_eq!(INIT.get().map(|r| *r), Some(2)); |
610 | | } |
611 | | |
612 | | #[test] |
613 | | fn get_no_wait() { |
614 | | static INIT: Once<usize> = Once::new(); |
615 | | |
616 | | assert!(INIT.get().is_none()); |
617 | | let t = thread::spawn(move || { |
618 | | INIT.call_once(|| { |
619 | | thread::sleep(std::time::Duration::from_secs(3)); |
620 | | 42 |
621 | | }); |
622 | | }); |
623 | | assert!(INIT.get().is_none()); |
624 | | |
625 | | t.join().unwrap(); |
626 | | } |
627 | | |
628 | | #[test] |
629 | | fn poll() { |
630 | | static INIT: Once<usize> = Once::new(); |
631 | | |
632 | | assert!(INIT.poll().is_none()); |
633 | | INIT.call_once(|| 3); |
634 | | assert_eq!(INIT.poll().map(|r| *r), Some(3)); |
635 | | } |
636 | | |
637 | | #[test] |
638 | | fn wait() { |
639 | | static INIT: Once<usize> = Once::new(); |
640 | | |
641 | | let t = std::thread::spawn(|| { |
642 | | assert_eq!(*INIT.wait(), 3); |
643 | | assert!(INIT.is_completed()); |
644 | | }); |
645 | | |
646 | | for _ in 0..4 { |
647 | | thread::yield_now() |
648 | | } |
649 | | |
650 | | assert!(INIT.poll().is_none()); |
651 | | INIT.call_once(|| 3); |
652 | | |
653 | | t.join().unwrap(); |
654 | | } |
655 | | |
656 | | #[test] |
657 | | fn panic() { |
658 | | use std::panic; |
659 | | |
660 | | static INIT: Once = Once::new(); |
661 | | |
662 | | // poison the once |
663 | | let t = panic::catch_unwind(|| { |
664 | | INIT.call_once(|| panic!()); |
665 | | }); |
666 | | assert!(t.is_err()); |
667 | | |
668 | | // poisoning propagates |
669 | | let t = panic::catch_unwind(|| { |
670 | | INIT.call_once(|| {}); |
671 | | }); |
672 | | assert!(t.is_err()); |
673 | | } |
674 | | |
675 | | #[test] |
676 | | fn init_constant() { |
677 | | static O: Once = Once::INIT; |
678 | | let mut a = 0; |
679 | | O.call_once(|| a += 1); |
680 | | assert_eq!(a, 1); |
681 | | O.call_once(|| a += 1); |
682 | | assert_eq!(a, 1); |
683 | | } |
684 | | |
685 | | static mut CALLED: bool = false; |
686 | | |
687 | | struct DropTest {} |
688 | | |
689 | | impl Drop for DropTest { |
690 | | fn drop(&mut self) { |
691 | | unsafe { |
692 | | CALLED = true; |
693 | | } |
694 | | } |
695 | | } |
696 | | |
697 | | #[test] |
698 | | fn try_call_once_err() { |
699 | | let once = Once::<_, Spin>::new(); |
700 | | let shared = Arc::new((once, AtomicU32::new(0))); |
701 | | |
702 | | let (tx, rx) = channel(); |
703 | | |
704 | | let t0 = { |
705 | | let shared = shared.clone(); |
706 | | thread::spawn(move || { |
707 | | let (once, called) = &*shared; |
708 | | |
709 | | once.try_call_once(|| { |
710 | | called.fetch_add(1, Ordering::AcqRel); |
711 | | tx.send(()).unwrap(); |
712 | | thread::sleep(std::time::Duration::from_millis(50)); |
713 | | Err(()) |
714 | | }) |
715 | | .ok(); |
716 | | }) |
717 | | }; |
718 | | |
719 | | let t1 = { |
720 | | let shared = shared.clone(); |
721 | | thread::spawn(move || { |
722 | | rx.recv().unwrap(); |
723 | | let (once, called) = &*shared; |
724 | | assert_eq!( |
725 | | called.load(Ordering::Acquire), |
726 | | 1, |
727 | | "leader thread did not run first" |
728 | | ); |
729 | | |
730 | | once.call_once(|| { |
731 | | called.fetch_add(1, Ordering::AcqRel); |
732 | | }); |
733 | | }) |
734 | | }; |
735 | | |
736 | | t0.join().unwrap(); |
737 | | t1.join().unwrap(); |
738 | | |
739 | | assert_eq!(shared.1.load(Ordering::Acquire), 2); |
740 | | } |
741 | | |
742 | | // This is sort of two test cases, but if we write them as separate test methods |
743 | | // they can be executed concurrently and then fail some small fraction of the |
744 | | // time. |
745 | | #[test] |
746 | | fn drop_occurs_and_skip_uninit_drop() { |
747 | | unsafe { |
748 | | CALLED = false; |
749 | | } |
750 | | |
751 | | { |
752 | | let once = Once::<_>::new(); |
753 | | once.call_once(|| DropTest {}); |
754 | | } |
755 | | |
756 | | assert!(unsafe { CALLED }); |
757 | | // Now test that we skip drops for the uninitialized case. |
758 | | unsafe { |
759 | | CALLED = false; |
760 | | } |
761 | | |
762 | | let once = Once::<DropTest>::new(); |
763 | | drop(once); |
764 | | |
765 | | assert!(unsafe { !CALLED }); |
766 | | } |
767 | | |
768 | | #[test] |
769 | | fn call_once_test() { |
770 | | for _ in 0..20 { |
771 | | use std::sync::atomic::AtomicUsize; |
772 | | use std::sync::Arc; |
773 | | use std::time::Duration; |
774 | | let share = Arc::new(AtomicUsize::new(0)); |
775 | | let once = Arc::new(Once::<_, Spin>::new()); |
776 | | let mut hs = Vec::new(); |
777 | | for _ in 0..8 { |
778 | | let h = thread::spawn({ |
779 | | let share = share.clone(); |
780 | | let once = once.clone(); |
781 | | move || { |
782 | | thread::sleep(Duration::from_millis(10)); |
783 | | once.call_once(|| { |
784 | | share.fetch_add(1, Ordering::SeqCst); |
785 | | }); |
786 | | } |
787 | | }); |
788 | | hs.push(h); |
789 | | } |
790 | | for h in hs { |
791 | | h.join().unwrap(); |
792 | | } |
793 | | assert_eq!(1, share.load(Ordering::SeqCst)); |
794 | | } |
795 | | } |
796 | | |
797 | | #[test] |
798 | | fn init_from_ref_basic() { |
799 | | let once = Once::<usize, Spin>::new(); |
800 | | |
801 | | let first = 1usize; |
802 | | let second = 2usize; |
803 | | assert_eq!(*once.init_from_ref(&first), 1); |
804 | | assert_eq!(*once.init_from_ref(&second), 1); |
805 | | } |
806 | | |
807 | | #[test] |
808 | | fn drop_boxed() { |
809 | | let boxed = Box::new(5); |
810 | | let once = Once::<_, Spin>::initialized(boxed); |
811 | | let boxed = once.try_into_inner().unwrap(); |
812 | | println!("{}", boxed); |
813 | | } |
814 | | } |