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