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