spin/once.rs
1//! Synchronization primitives for one-time evaluation.
2
3use crate::{
4 atomic::{AtomicU8, Ordering},
5 RelaxStrategy, Spin,
6};
7use 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/// ```
33pub struct Once<T = (), R = Spin> {
34 phantom: PhantomData<R>,
35 status: AtomicStatus,
36 data: UnsafeCell<MaybeUninit<T>>,
37}
38
39impl<T, R> Default for Once<T, R> {
40 fn default() -> Self {
41 Self::new()
42 }
43}
44
45impl<T: fmt::Debug, R> fmt::Debug for Once<T, R> {
46 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
47 match self.get() {
48 Some(s) => write!(f, "Once {{ data: ")
49 .and_then(|()| s.fmt(f))
50 .and_then(|()| write!(f, "}}")),
51 None => write!(f, "Once {{ <uninitialized> }}"),
52 }
53 }
54}
55
56// Same unsafe impls as `std::sync::RwLock`, because this also allows for
57// concurrent reads.
58unsafe impl<T: Send + Sync, R> Sync for Once<T, R> {}
59unsafe impl<T: Send, R> Send for Once<T, R> {}
60
61mod 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 unsafe fn new_unchecked(inner: u8) -> Self {
87 core::mem::transmute(inner)
88 }
89 }
90
91 impl AtomicStatus {
92 #[inline(always)]
93 pub const fn new(status: Status) -> Self {
94 // SAFETY: We got the value directly from status, so transmuting back is fine.
95 Self(AtomicU8::new(status as u8))
96 }
97 #[inline(always)]
98 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 unsafe { Status::new_unchecked(self.0.load(ordering)) }
102 }
103 #[inline(always)]
104 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 self.0.store(status as u8, ordering);
108 }
109 #[inline(always)]
110 pub fn compare_exchange(
111 &self,
112 old: Status,
113 new: Status,
114 success: Ordering,
115 failure: Ordering,
116 ) -> Result<Status, Status> {
117 match self
118 .0
119 .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 Ok(ok) => Ok(unsafe { Status::new_unchecked(ok) }),
125 Err(err) => Err(unsafe { Status::new_unchecked(err) }),
126 }
127 }
128 #[inline(always)]
129 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 unsafe { &mut *((self.0.get_mut() as *mut u8).cast::<Status>()) }
133 }
134 }
135}
136use self::status::{AtomicStatus, Status};
137
138impl<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 pub fn call_once<F: FnOnce() -> T>(&self, f: F) -> &T {
174 match self.try_call_once(|| Ok::<T, core::convert::Infallible>(f())) {
175 Ok(x) => x,
176 Err(void) => match void {},
177 }
178 }
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 pub fn try_call_once<F: FnOnce() -> Result<T, E>, E>(&self, f: F) -> Result<&T, E> {
214 if let Some(value) = self.get() {
215 Ok(value)
216 } else {
217 self.try_call_once_slow(f)
218 }
219 }
220
221 #[cold]
222 fn try_call_once_slow<F: FnOnce() -> Result<T, E>, E>(&self, f: F) -> Result<&T, E> {
223 loop {
224 let xchg = self.status.compare_exchange(
225 Status::Incomplete,
226 Status::Running,
227 Ordering::Acquire,
228 Ordering::Acquire,
229 );
230
231 match xchg {
232 Ok(_must_be_state_incomplete) => {
233 // Impl is defined after the match for readability
234 }
235 Err(Status::Panicked) => panic!("Once panicked"),
236 Err(Status::Running) => match self.poll() {
237 Some(v) => return Ok(v),
238 None => continue,
239 },
240 Err(Status::Complete) => {
241 return Ok(unsafe {
242 // SAFETY: The status is Complete
243 self.force_get()
244 });
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 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 let finish = Finish {
258 status: &self.status,
259 };
260 let val = match f() {
261 Ok(val) => val,
262 Err(err) => {
263 // If an error occurs, clean up everything and leave.
264 core::mem::forget(finish);
265 self.status.store(Status::Incomplete, Ordering::Release);
266 return Err(err);
267 }
268 };
269 unsafe {
270 // SAFETY:
271 // `UnsafeCell`/deref: currently the only accessor, mutably
272 // and immutably by cas exclusion.
273 // `write`: pointer comes from `MaybeUninit`.
274 (*self.data.get()).as_mut_ptr().write(val);
275 };
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 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 self.status.store(Status::Complete, Ordering::Release);
296
297 // This next line is mainly an optimization.
298 return unsafe { Ok(self.force_get()) };
299 }
300 }
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 pub fn wait(&self) -> &T {
312 loop {
313 match self.poll() {
314 Some(x) => break x,
315 None => R::relax(),
316 }
317 }
318 }
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 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 match self.status.load(Ordering::Acquire) {
336 Status::Incomplete => return None,
337 Status::Running => R::relax(), // We spin
338 Status::Complete => return Some(unsafe { self.force_get() }),
339 Status::Panicked => panic!("Once previously poisoned by a panicked"),
340 }
341 }
342 }
343}
344
345impl<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 pub const fn new() -> Self {
356 Self::INIT
357 }
358
359 /// Creates a new initialized [`Once`].
360 pub const fn initialized(data: T) -> Self {
361 Self {
362 phantom: PhantomData,
363 status: AtomicStatus::new(Status::Complete),
364 data: UnsafeCell::new(MaybeUninit::new(data)),
365 }
366 }
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 pub fn as_mut_ptr(&self) -> *mut T {
374 // SAFETY:
375 // * MaybeUninit<T> always has exactly the same layout as T
376 self.data.get().cast::<T>()
377 }
378
379 /// Get a reference to the initialized instance. Must only be called once COMPLETE.
380 unsafe fn force_get(&self) -> &T {
381 // SAFETY:
382 // * `UnsafeCell`/inner deref: data never changes again
383 // * `MaybeUninit`/outer deref: data was initialized
384 &*(*self.data.get()).as_ptr()
385 }
386
387 /// Get a reference to the initialized instance. Must only be called once COMPLETE.
388 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 &mut *(*self.data.get()).as_mut_ptr()
393 }
394
395 /// Get a reference to the initialized instance. Must only be called once COMPLETE.
396 unsafe fn force_into_inner(self) -> T {
397 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 this.data.get_mut().assume_init_read()
403 }
404
405 /// Returns a reference to the inner value if the [`Once`] has been initialized.
406 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 match self.status.load(Ordering::Acquire) {
410 Status::Complete => Some(unsafe { self.force_get() }),
411 _ => None,
412 }
413 }
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 pub unsafe fn get_unchecked(&self) -> &T {
424 debug_assert_eq!(
425 self.status.load(Ordering::SeqCst),
426 Status::Complete,
427 "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 self.force_get()
430 }
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 pub fn get_mut(&mut self) -> Option<&mut T> {
437 match *self.status.get_mut() {
438 Status::Complete => Some(unsafe { self.force_get_mut() }),
439 _ => None,
440 }
441 }
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 pub unsafe fn get_mut_unchecked(&mut self) -> &mut T {
452 debug_assert_eq!(
453 self.status.load(Ordering::SeqCst),
454 Status::Complete,
455 "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 self.force_get_mut()
458 }
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 pub fn try_into_inner(mut self) -> Option<T> {
465 match *self.status.get_mut() {
466 Status::Complete => Some(unsafe { self.force_into_inner() }),
467 _ => None,
468 }
469 }
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 pub unsafe fn into_inner_unchecked(self) -> T {
479 debug_assert_eq!(
480 self.status.load(Ordering::SeqCst),
481 Status::Complete,
482 "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 self.force_into_inner()
485 }
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 pub fn is_completed(&self) -> bool {
493 // TODO: Add a similar variant for Relaxed?
494 self.status.load(Ordering::Acquire) == Status::Complete
495 }
496}
497
498impl<T, R> From<T> for Once<T, R> {
499 fn from(data: T) -> Self {
500 Self::initialized(data)
501 }
502}
503
504impl<T, R> Drop for Once<T, R> {
505 fn drop(&mut self) {
506 // No need to do any atomic access here, we have &mut!
507 if *self.status.get_mut() == Status::Complete {
508 unsafe {
509 //TODO: Use MaybeUninit::assume_init_drop once stabilised
510 core::ptr::drop_in_place((*self.data.get()).as_mut_ptr());
511 }
512 }
513 }
514}
515
516struct Finish<'a> {
517 status: &'a AtomicStatus,
518}
519
520impl<'a> Drop for Finish<'a> {
521 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 self.status.store(Status::Panicked, Ordering::SeqCst);
529 }
530}
531
532#[cfg(test)]
533mod 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}