Skip to main content

parking_lot/
once.rs

1// Copyright 2016 Amanieu d'Antras
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use crate::util::UncheckedOptionExt;
9use core::{
10    fmt, mem,
11    sync::atomic::{fence, AtomicU8, Ordering},
12};
13use parking_lot_core::{self, SpinWait, DEFAULT_PARK_TOKEN, DEFAULT_UNPARK_TOKEN};
14
15const DONE_BIT: u8 = 1;
16const POISON_BIT: u8 = 2;
17const LOCKED_BIT: u8 = 4;
18const PARKED_BIT: u8 = 8;
19
20/// Current state of a `Once`.
21#[derive(Copy, Clone, Eq, PartialEq, Debug)]
22pub enum OnceState {
23    /// A closure has not been executed yet
24    New,
25
26    /// A closure was executed but panicked.
27    Poisoned,
28
29    /// A thread is currently executing a closure.
30    InProgress,
31
32    /// A closure has completed successfully.
33    Done,
34}
35
36impl OnceState {
37    /// Returns whether the associated `Once` has been poisoned.
38    ///
39    /// Once an initialization routine for a `Once` has panicked it will forever
40    /// indicate to future forced initialization routines that it is poisoned.
41    #[inline]
42    pub fn poisoned(self) -> bool {
43        matches!(self, OnceState::Poisoned)
44    }
45
46    /// Returns whether the associated `Once` has successfully executed a
47    /// closure.
48    #[inline]
49    pub fn done(self) -> bool {
50        matches!(self, OnceState::Done)
51    }
52}
53
54/// A synchronization primitive which can be used to run a one-time
55/// initialization. Useful for one-time initialization for globals, FFI or
56/// related functionality.
57///
58/// # Differences from the standard library `Once`
59///
60/// - Only requires 1 byte of space, instead of 1 word.
61/// - Not required to be `'static`.
62/// - Relaxed memory barriers in the fast path, which can significantly improve
63///   performance on some architectures.
64/// - Efficient handling of micro-contention using adaptive spinning.
65///
66/// # Examples
67///
68/// ```
69/// use parking_lot::Once;
70///
71/// static START: Once = Once::new();
72///
73/// START.call_once(|| {
74///     // run initialization here
75/// });
76/// ```
77pub struct Once(AtomicU8);
78
79impl Once {
80    /// Creates a new `Once` value.
81    #[inline]
82    pub const fn new() -> Once {
83        Once(AtomicU8::new(0))
84    }
85
86    /// Creates a new `Once` value that is already in the completed state.
87    ///
88    /// A `Once` created this way will never invoke a closure passed to
89    /// [`call_once`](Self::call_once) or [`call_once_force`](Self::call_once_force),
90    /// and its [`state`](Self::state) will always be [`OnceState::Done`].
91    ///
92    /// # Examples
93    ///
94    /// ```
95    /// use parking_lot::{Once, OnceState};
96    ///
97    /// static INIT: Once = Once::new_completed();
98    /// assert_eq!(INIT.state(), OnceState::Done);
99    ///
100    /// // The closure is never executed.
101    /// INIT.call_once(|| unreachable!());
102    /// ```
103    #[inline]
104    pub const fn new_completed() -> Once {
105        Once(AtomicU8::new(DONE_BIT))
106    }
107
108    /// Returns the current state of this `Once`.
109    #[inline]
110    pub fn state(&self) -> OnceState {
111        let state = self.0.load(Ordering::Acquire);
112        if state & DONE_BIT != 0 {
113            OnceState::Done
114        } else if state & LOCKED_BIT != 0 {
115            OnceState::InProgress
116        } else if state & POISON_BIT != 0 {
117            OnceState::Poisoned
118        } else {
119            OnceState::New
120        }
121    }
122
123    /// Performs an initialization routine once and only once. The given closure
124    /// will be executed if this is the first time `call_once` has been called,
125    /// and otherwise the routine will *not* be invoked.
126    ///
127    /// This method will block the calling thread if another initialization
128    /// routine is currently running.
129    ///
130    /// When this function returns, it is guaranteed that some initialization
131    /// has run and completed (it may not be the closure specified). It is also
132    /// guaranteed that any memory writes performed by the executed closure can
133    /// be reliably observed by other threads at this point (there is a
134    /// happens-before relation between the closure and code executing after the
135    /// return).
136    ///
137    /// # Examples
138    ///
139    /// ```
140    /// use parking_lot::Once;
141    ///
142    /// static mut VAL: usize = 0;
143    /// static INIT: Once = Once::new();
144    ///
145    /// // Accessing a `static mut` is unsafe much of the time, but if we do so
146    /// // in a synchronized fashion (e.g. write once or read all) then we're
147    /// // good to go!
148    /// //
149    /// // This function will only call `expensive_computation` once, and will
150    /// // otherwise always return the value returned from the first invocation.
151    /// fn get_cached_val() -> usize {
152    ///     unsafe {
153    ///         INIT.call_once(|| {
154    ///             VAL = expensive_computation();
155    ///         });
156    ///         VAL
157    ///     }
158    /// }
159    ///
160    /// fn expensive_computation() -> usize {
161    ///     // ...
162    /// # 2
163    /// }
164    /// ```
165    ///
166    /// # Panics
167    ///
168    /// The closure `f` will only be executed once if this is called
169    /// concurrently amongst many threads. If that closure panics, however, then
170    /// it will *poison* this `Once` instance, causing all future invocations of
171    /// `call_once` to also panic.
172    #[inline]
173    pub fn call_once<F>(&self, f: F)
174    where
175        F: FnOnce(),
176    {
177        if self.0.load(Ordering::Acquire) == DONE_BIT {
178            return;
179        }
180
181        let mut f = Some(f);
182        self.call_once_slow(false, &mut |_| unsafe { f.take().unchecked_unwrap()() });
183    }
184
185    /// Performs the same function as `call_once` except ignores poisoning.
186    ///
187    /// If this `Once` has been poisoned (some initialization panicked) then
188    /// this function will continue to attempt to call initialization functions
189    /// until one of them doesn't panic.
190    ///
191    /// The closure `f` is yielded a structure which can be used to query the
192    /// state of this `Once` (whether initialization has previously panicked or
193    /// not).
194    #[inline]
195    pub fn call_once_force<F>(&self, f: F)
196    where
197        F: FnOnce(OnceState),
198    {
199        if self.0.load(Ordering::Acquire) == DONE_BIT {
200            return;
201        }
202
203        let mut f = Some(f);
204        self.call_once_slow(true, &mut |state| unsafe {
205            f.take().unchecked_unwrap()(state)
206        });
207    }
208
209    // This is a non-generic function to reduce the monomorphization cost of
210    // using `call_once` (this isn't exactly a trivial or small implementation).
211    //
212    // Additionally, this is tagged with `#[cold]` as it should indeed be cold
213    // and it helps let LLVM know that calls to this function should be off the
214    // fast path. Essentially, this should help generate more straight line code
215    // in LLVM.
216    //
217    // Finally, this takes an `FnMut` instead of a `FnOnce` because there's
218    // currently no way to take an `FnOnce` and call it via virtual dispatch
219    // without some allocation overhead.
220    #[cold]
221    fn call_once_slow(&self, ignore_poison: bool, f: &mut dyn FnMut(OnceState)) {
222        let mut spinwait = SpinWait::new();
223        let mut state = self.0.load(Ordering::Relaxed);
224        loop {
225            // If another thread called the closure, we're done
226            if state & DONE_BIT != 0 {
227                // An acquire fence is needed here since we didn't load the
228                // state with Ordering::Acquire.
229                fence(Ordering::Acquire);
230                return;
231            }
232
233            // If the state has been poisoned and we aren't forcing, then panic
234            if state & POISON_BIT != 0 && !ignore_poison {
235                // Need the fence here as well for the same reason
236                fence(Ordering::Acquire);
237                panic!("Once instance has previously been poisoned");
238            }
239
240            // Grab the lock if it isn't locked, even if there is a queue on it.
241            // We also clear the poison bit since we are going to try running
242            // the closure again.
243            if state & LOCKED_BIT == 0 {
244                match self.0.compare_exchange_weak(
245                    state,
246                    (state | LOCKED_BIT) & !POISON_BIT,
247                    Ordering::Acquire,
248                    Ordering::Relaxed,
249                ) {
250                    Ok(_) => break,
251                    Err(x) => state = x,
252                }
253                continue;
254            }
255
256            // If there is no queue, try spinning a few times
257            if state & PARKED_BIT == 0 && spinwait.spin() {
258                state = self.0.load(Ordering::Relaxed);
259                continue;
260            }
261
262            // Set the parked bit
263            if state & PARKED_BIT == 0 {
264                if let Err(x) = self.0.compare_exchange_weak(
265                    state,
266                    state | PARKED_BIT,
267                    Ordering::Relaxed,
268                    Ordering::Relaxed,
269                ) {
270                    state = x;
271                    continue;
272                }
273            }
274
275            // Park our thread until we are woken up by the thread that owns the
276            // lock.
277            let addr = self as *const _ as usize;
278            let validate = || self.0.load(Ordering::Relaxed) == LOCKED_BIT | PARKED_BIT;
279            let before_sleep = || {};
280            let timed_out = |_, _| unreachable!();
281            unsafe {
282                parking_lot_core::park(
283                    addr,
284                    validate,
285                    before_sleep,
286                    timed_out,
287                    DEFAULT_PARK_TOKEN,
288                    None,
289                );
290            }
291
292            // Loop back and check if the done bit was set
293            spinwait.reset();
294            state = self.0.load(Ordering::Relaxed);
295        }
296
297        struct PanicGuard<'a>(&'a Once);
298        impl<'a> Drop for PanicGuard<'a> {
299            fn drop(&mut self) {
300                // Mark the state as poisoned, unlock it and unpark all threads.
301                let once = self.0;
302                let state = once.0.swap(POISON_BIT, Ordering::Release);
303                if state & PARKED_BIT != 0 {
304                    let addr = once as *const _ as usize;
305                    unsafe {
306                        parking_lot_core::unpark_all(addr, DEFAULT_UNPARK_TOKEN);
307                    }
308                }
309            }
310        }
311
312        // At this point we have the lock, so run the closure. Make sure we
313        // properly clean up if the closure panicks.
314        let guard = PanicGuard(self);
315        let once_state = if state & POISON_BIT != 0 {
316            OnceState::Poisoned
317        } else {
318            OnceState::New
319        };
320        f(once_state);
321        mem::forget(guard);
322
323        // Now unlock the state, set the done bit and unpark all threads
324        let state = self.0.swap(DONE_BIT, Ordering::Release);
325        if state & PARKED_BIT != 0 {
326            let addr = self as *const _ as usize;
327            unsafe {
328                parking_lot_core::unpark_all(addr, DEFAULT_UNPARK_TOKEN);
329            }
330        }
331    }
332}
333
334impl Default for Once {
335    #[inline]
336    fn default() -> Once {
337        Once::new()
338    }
339}
340
341impl fmt::Debug for Once {
342    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343        f.debug_struct("Once")
344            .field("state", &self.state())
345            .finish()
346    }
347}
348
349#[cfg(test)]
350mod tests {
351    use crate::Once;
352    use std::panic;
353    use std::sync::mpsc::channel;
354    use std::thread;
355
356    #[test]
357    fn smoke_once() {
358        static O: Once = Once::new();
359        let mut a = 0;
360        O.call_once(|| a += 1);
361        assert_eq!(a, 1);
362        O.call_once(|| a += 1);
363        assert_eq!(a, 1);
364    }
365
366    #[test]
367    fn stampede_once() {
368        static O: Once = Once::new();
369        static mut RUN: bool = false;
370
371        let (tx, rx) = channel();
372        for _ in 0..10 {
373            let tx = tx.clone();
374            thread::spawn(move || {
375                for _ in 0..4 {
376                    thread::yield_now()
377                }
378                unsafe {
379                    O.call_once(|| {
380                        assert!(!RUN);
381                        RUN = true;
382                    });
383                    assert!(RUN);
384                }
385                tx.send(()).unwrap();
386            });
387        }
388
389        unsafe {
390            O.call_once(|| {
391                assert!(!RUN);
392                RUN = true;
393            });
394            assert!(RUN);
395        }
396
397        for _ in 0..10 {
398            rx.recv().unwrap();
399        }
400    }
401
402    #[test]
403    fn poison_bad() {
404        static O: Once = Once::new();
405
406        // poison the once
407        let t = panic::catch_unwind(|| {
408            O.call_once(|| panic!());
409        });
410        assert!(t.is_err());
411
412        // poisoning propagates
413        let t = panic::catch_unwind(|| {
414            O.call_once(|| {});
415        });
416        assert!(t.is_err());
417
418        // we can subvert poisoning, however
419        let mut called = false;
420        O.call_once_force(|p| {
421            called = true;
422            assert!(p.poisoned())
423        });
424        assert!(called);
425
426        // once any success happens, we stop propagating the poison
427        O.call_once(|| {});
428    }
429
430    #[test]
431    fn wait_for_force_to_finish() {
432        static O: Once = Once::new();
433
434        // poison the once
435        let t = panic::catch_unwind(|| {
436            O.call_once(|| panic!());
437        });
438        assert!(t.is_err());
439
440        // make sure someone's waiting inside the once via a force
441        let (tx1, rx1) = channel();
442        let (tx2, rx2) = channel();
443        let t1 = thread::spawn(move || {
444            O.call_once_force(|p| {
445                assert!(p.poisoned());
446                tx1.send(()).unwrap();
447                rx2.recv().unwrap();
448            });
449        });
450
451        rx1.recv().unwrap();
452
453        // put another waiter on the once
454        let t2 = thread::spawn(|| {
455            let mut called = false;
456            O.call_once(|| {
457                called = true;
458            });
459            assert!(!called);
460        });
461
462        tx2.send(()).unwrap();
463
464        assert!(t1.join().is_ok());
465        assert!(t2.join().is_ok());
466    }
467
468    #[test]
469    fn test_once_debug() {
470        static O: Once = Once::new();
471
472        assert_eq!(format!("{:?}", O), "Once { state: New }");
473    }
474
475    #[test]
476    fn new_completed_is_done() {
477        use crate::OnceState;
478
479        static O: Once = Once::new_completed();
480        assert_eq!(O.state(), OnceState::Done);
481        assert!(O.state().done());
482        assert!(!O.state().poisoned());
483
484        let mut called = false;
485        O.call_once(|| called = true);
486        assert!(!called);
487        assert_eq!(O.state(), OnceState::Done);
488    }
489
490    #[test]
491    fn new_default_is_new() {
492        // Sanity check that the default constructor is unchanged.
493        static O: Once = Once::new();
494        let mut called = false;
495        O.call_once(|| called = true);
496        assert!(called);
497    }
498}