1 // Copyright 2016 Amanieu d'Antras
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.
8 use crate::util
::UncheckedOptionExt
;
11 sync
::atomic
::{fence, AtomicU8, Ordering}
,
13 use parking_lot_core
::{self, SpinWait, DEFAULT_PARK_TOKEN, DEFAULT_UNPARK_TOKEN}
;
15 const DONE_BIT
: u8 = 1;
16 const POISON_BIT
: u8 = 2;
17 const LOCKED_BIT
: u8 = 4;
18 const PARKED_BIT
: u8 = 8;
20 /// Current state of a `Once`.
21 #[derive(Copy, Clone, Eq, PartialEq, Debug)]
23 /// A closure has not been executed yet
26 /// A closure was executed but panicked.
29 /// A thread is currently executing a closure.
32 /// A closure has completed successfully.
37 /// Returns whether the associated `Once` has been poisoned.
39 /// Once an initialization routine for a `Once` has panicked it will forever
40 /// indicate to future forced initialization routines that it is poisoned.
42 pub fn poisoned(self) -> bool
{
44 OnceState
::Poisoned
=> true,
49 /// Returns whether the associated `Once` has successfully executed a
52 pub fn done(self) -> bool
{
54 OnceState
::Done
=> true,
60 /// A synchronization primitive which can be used to run a one-time
61 /// initialization. Useful for one-time initialization for globals, FFI or
62 /// related functionality.
64 /// # Differences from the standard library `Once`
66 /// - Only requires 1 byte of space, instead of 1 word.
67 /// - Not required to be `'static`.
68 /// - Relaxed memory barriers in the fast path, which can significantly improve
69 /// performance on some architectures.
70 /// - Efficient handling of micro-contention using adaptive spinning.
75 /// use parking_lot::Once;
77 /// static START: Once = Once::new();
79 /// START.call_once(|| {
80 /// // run initialization here
83 pub struct Once(AtomicU8
);
86 /// Creates a new `Once` value.
88 pub const fn new() -> Once
{
89 Once(AtomicU8
::new(0))
92 /// Returns the current state of this `Once`.
94 pub fn state(&self) -> OnceState
{
95 let state
= self.0.load(Ordering
::Acquire
);
96 if state
& DONE_BIT
!= 0 {
98 } else if state
& LOCKED_BIT
!= 0 {
100 } else if state
& POISON_BIT
!= 0 {
107 /// Performs an initialization routine once and only once. The given closure
108 /// will be executed if this is the first time `call_once` has been called,
109 /// and otherwise the routine will *not* be invoked.
111 /// This method will block the calling thread if another initialization
112 /// routine is currently running.
114 /// When this function returns, it is guaranteed that some initialization
115 /// has run and completed (it may not be the closure specified). It is also
116 /// guaranteed that any memory writes performed by the executed closure can
117 /// be reliably observed by other threads at this point (there is a
118 /// happens-before relation between the closure and code executing after the
124 /// use parking_lot::Once;
126 /// static mut VAL: usize = 0;
127 /// static INIT: Once = Once::new();
129 /// // Accessing a `static mut` is unsafe much of the time, but if we do so
130 /// // in a synchronized fashion (e.g. write once or read all) then we're
133 /// // This function will only call `expensive_computation` once, and will
134 /// // otherwise always return the value returned from the first invocation.
135 /// fn get_cached_val() -> usize {
137 /// INIT.call_once(|| {
138 /// VAL = expensive_computation();
144 /// fn expensive_computation() -> usize {
152 /// The closure `f` will only be executed once if this is called
153 /// concurrently amongst many threads. If that closure panics, however, then
154 /// it will *poison* this `Once` instance, causing all future invocations of
155 /// `call_once` to also panic.
157 pub fn call_once
<F
>(&self, f
: F
)
161 if self.0.load(Ordering
::Acquire
) == DONE_BIT
{
166 self.call_once_slow(false, &mut |_
| unsafe { f.take().unchecked_unwrap()() }
);
169 /// Performs the same function as `call_once` except ignores poisoning.
171 /// If this `Once` has been poisoned (some initialization panicked) then
172 /// this function will continue to attempt to call initialization functions
173 /// until one of them doesn't panic.
175 /// The closure `f` is yielded a structure which can be used to query the
176 /// state of this `Once` (whether initialization has previously panicked or
179 pub fn call_once_force
<F
>(&self, f
: F
)
181 F
: FnOnce(OnceState
),
183 if self.0.load(Ordering
::Acquire
) == DONE_BIT
{
188 self.call_once_slow(true, &mut |state
| unsafe {
189 f
.take().unchecked_unwrap()(state
)
193 // This is a non-generic function to reduce the monomorphization cost of
194 // using `call_once` (this isn't exactly a trivial or small implementation).
196 // Additionally, this is tagged with `#[cold]` as it should indeed be cold
197 // and it helps let LLVM know that calls to this function should be off the
198 // fast path. Essentially, this should help generate more straight line code
201 // Finally, this takes an `FnMut` instead of a `FnOnce` because there's
202 // currently no way to take an `FnOnce` and call it via virtual dispatch
203 // without some allocation overhead.
205 fn call_once_slow(&self, ignore_poison
: bool
, f
: &mut dyn FnMut(OnceState
)) {
206 let mut spinwait
= SpinWait
::new();
207 let mut state
= self.0.load(Ordering
::Relaxed
);
209 // If another thread called the closure, we're done
210 if state
& DONE_BIT
!= 0 {
211 // An acquire fence is needed here since we didn't load the
212 // state with Ordering::Acquire.
213 fence(Ordering
::Acquire
);
217 // If the state has been poisoned and we aren't forcing, then panic
218 if state
& POISON_BIT
!= 0 && !ignore_poison
{
219 // Need the fence here as well for the same reason
220 fence(Ordering
::Acquire
);
221 panic
!("Once instance has previously been poisoned");
224 // Grab the lock if it isn't locked, even if there is a queue on it.
225 // We also clear the poison bit since we are going to try running
226 // the closure again.
227 if state
& LOCKED_BIT
== 0 {
228 match self.0.compare_exchange_weak(
230 (state
| LOCKED_BIT
) & !POISON_BIT
,
240 // If there is no queue, try spinning a few times
241 if state
& PARKED_BIT
== 0 && spinwait
.spin() {
242 state
= self.0.load(Ordering
::Relaxed
);
246 // Set the parked bit
247 if state
& PARKED_BIT
== 0 {
248 if let Err(x
) = self.0.compare_exchange_weak(
259 // Park our thread until we are woken up by the thread that owns the
262 let addr
= self as *const _
as usize;
263 let validate
= || self.0.load(Ordering
::Relaxed
) == LOCKED_BIT
| PARKED_BIT
;
264 let before_sleep
= || {}
;
265 let timed_out
= |_
, _
| unreachable
!();
266 parking_lot_core
::park(
276 // Loop back and check if the done bit was set
278 state
= self.0.load(Ordering
::Relaxed
);
281 struct PanicGuard
<'a
>(&'a Once
);
282 impl<'a
> Drop
for PanicGuard
<'a
> {
284 // Mark the state as poisoned, unlock it and unpark all threads.
286 let state
= once
.0.swap(POISON_BIT
, Ordering
::Release
);
287 if state
& PARKED_BIT
!= 0 {
289 let addr
= once
as *const _
as usize;
290 parking_lot_core
::unpark_all(addr
, DEFAULT_UNPARK_TOKEN
);
296 // At this point we have the lock, so run the closure. Make sure we
297 // properly clean up if the closure panicks.
298 let guard
= PanicGuard(self);
299 let once_state
= if state
& POISON_BIT
!= 0 {
307 // Now unlock the state, set the done bit and unpark all threads
308 let state
= self.0.swap(DONE_BIT
, Ordering
::Release
);
309 if state
& PARKED_BIT
!= 0 {
311 let addr
= self as *const _
as usize;
312 parking_lot_core
::unpark_all(addr
, DEFAULT_UNPARK_TOKEN
);
318 impl Default
for Once
{
320 fn default() -> Once
{
325 impl fmt
::Debug
for Once
{
326 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
327 f
.debug_struct("Once")
328 .field("state", &self.state())
337 use std
::sync
::mpsc
::channel
;
342 static O
: Once
= Once
::new();
344 O
.call_once(|| a
+= 1);
346 O
.call_once(|| a
+= 1);
352 static O
: Once
= Once
::new();
353 static mut RUN
: bool
= false;
355 let (tx
, rx
) = channel();
358 thread
::spawn(move || {
369 tx
.send(()).unwrap();
388 static O
: Once
= Once
::new();
391 let t
= panic
::catch_unwind(|| {
392 O
.call_once(|| panic
!());
396 // poisoning propagates
397 let t
= panic
::catch_unwind(|| {
402 // we can subvert poisoning, however
403 let mut called
= false;
404 O
.call_once_force(|p
| {
406 assert
!(p
.poisoned())
410 // once any success happens, we stop propagating the poison
415 fn wait_for_force_to_finish() {
416 static O
: Once
= Once
::new();
419 let t
= panic
::catch_unwind(|| {
420 O
.call_once(|| panic
!());
424 // make sure someone's waiting inside the once via a force
425 let (tx1
, rx1
) = channel();
426 let (tx2
, rx2
) = channel();
427 let t1
= thread
::spawn(move || {
428 O
.call_once_force(|p
| {
429 assert
!(p
.poisoned());
430 tx1
.send(()).unwrap();
437 // put another waiter on the once
438 let t2
= thread
::spawn(|| {
439 let mut called
= false;
446 tx2
.send(()).unwrap();
448 assert
!(t1
.join().is_ok());
449 assert
!(t2
.join().is_ok());
453 fn test_once_debug() {
454 static O
: Once
= Once
::new();
456 assert_eq
!(format
!("{:?}", O
), "Once { state: New }");