Coverage Report

Created: 2025-11-16 06:35

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