parking_lot/once.rs
1use core::{
2 fmt, mem,
3 sync::atomic::{AtomicU8, Ordering, fence},
4};
5use parking_lot_core::{self, DEFAULT_PARK_TOKEN, DEFAULT_UNPARK_TOKEN, SpinWait};
6
7use crate::deadlock;
8
9const DONE_BIT: u8 = 1;
10const POISON_BIT: u8 = 2;
11const LOCKED_BIT: u8 = 4;
12const PARKED_BIT: u8 = 8;
13
14/// Current state of a `Once`.
15#[derive(Copy, Clone, Eq, PartialEq, Debug)]
16pub enum OnceState {
17 /// A closure has not been executed yet.
18 New,
19
20 /// A closure was executed but panicked.
21 Poisoned,
22
23 /// A thread is currently executing a closure.
24 InProgress,
25
26 /// A closure has completed successfully.
27 Done,
28}
29
30impl OnceState {
31 /// Returns `true` if this is the [`Poisoned`](OnceState::Poisoned) state.
32 /// When a state is passed to [`Once::call_once_force`], this indicates that
33 /// the [`Once`] was poisoned before the closure was invoked.
34 ///
35 /// # Examples
36 ///
37 /// A poisoned [`Once`]:
38 ///
39 /// ```
40 /// use parking_lot::Once;
41 /// use std::thread;
42 ///
43 /// static INIT: Once = Once::new();
44 ///
45 /// let handle = thread::spawn(|| {
46 /// INIT.call_once(|| panic!());
47 /// });
48 /// assert!(handle.join().is_err());
49 ///
50 /// INIT.call_once_force(|state| {
51 /// assert!(state.is_poisoned());
52 /// });
53 /// ```
54 ///
55 /// An unpoisoned [`Once`]:
56 ///
57 /// ```
58 /// use parking_lot::Once;
59 ///
60 /// static INIT: Once = Once::new();
61 ///
62 /// INIT.call_once_force(|state| {
63 /// assert!(!state.is_poisoned());
64 /// });
65 /// ```
66 #[inline]
67 pub const fn is_poisoned(self) -> bool {
68 matches!(self, OnceState::Poisoned)
69 }
70
71 /// Alias for [`is_poisoned`](Self::is_poisoned).
72 #[inline]
73 pub const fn poisoned(self) -> bool {
74 self.is_poisoned()
75 }
76
77 /// Returns `true` if this is the [`Done`](OnceState::Done) state.
78 #[inline]
79 pub const fn is_completed(self) -> bool {
80 matches!(self, OnceState::Done)
81 }
82
83 /// Alias for [`is_completed`](Self::is_completed).
84 #[inline]
85 pub const fn done(self) -> bool {
86 self.is_completed()
87 }
88}
89
90/// A synchronization primitive which can be used to run a one-time
91/// initialization. Useful for one-time initialization for globals, FFI or
92/// related functionality.
93///
94/// When the initialization produces a value, [`std::sync::OnceLock`] is often
95/// more convenient.
96///
97/// # Examples
98///
99/// ```
100/// use parking_lot::Once;
101///
102/// static START: Once = Once::new();
103///
104/// START.call_once(|| {
105/// // run initialization here
106/// });
107/// ```
108pub struct Once(AtomicU8);
109
110impl Once {
111 /// Creates a new `Once` value.
112 #[inline]
113 pub const fn new() -> Once {
114 Once(AtomicU8::new(0))
115 }
116
117 /// Creates a new `Once` value that is already in the completed state.
118 ///
119 /// A `Once` created this way will never invoke a closure passed to
120 /// [`call_once`](Self::call_once) or [`call_once_force`](Self::call_once_force),
121 /// and its [`state`](Self::state) will always be [`OnceState::Done`].
122 ///
123 /// # Examples
124 ///
125 /// ```
126 /// use parking_lot::{Once, OnceState};
127 ///
128 /// static INIT: Once = Once::new_completed();
129 /// assert_eq!(INIT.state(), OnceState::Done);
130 ///
131 /// // The closure is never executed.
132 /// INIT.call_once(|| unreachable!());
133 /// ```
134 #[inline]
135 pub const fn new_completed() -> Once {
136 Once(AtomicU8::new(DONE_BIT))
137 }
138
139 /// Returns a snapshot of the current state of this `Once`.
140 ///
141 /// The state may change immediately after this function returns.
142 #[inline]
143 pub fn state(&self) -> OnceState {
144 let state = self.0.load(Ordering::Acquire);
145 if state & DONE_BIT != 0 {
146 OnceState::Done
147 } else if state & LOCKED_BIT != 0 {
148 OnceState::InProgress
149 } else if state & POISON_BIT != 0 {
150 OnceState::Poisoned
151 } else {
152 OnceState::New
153 }
154 }
155
156 /// Returns `true` if this `Once` is in the completed state.
157 ///
158 /// A `Once` becomes completed when an initialization closure finishes
159 /// successfully, or when it is created with
160 /// [`new_completed`](Self::new_completed). This method returns `false` if
161 /// initialization has not started, is still in progress, or the `Once` is
162 /// poisoned.
163 ///
164 /// A `false` result may be stale. For example, initialization may complete
165 /// between the state being read and this function returning.
166 ///
167 /// # Examples
168 ///
169 /// ```
170 /// use parking_lot::Once;
171 ///
172 /// static INIT: Once = Once::new();
173 ///
174 /// assert!(!INIT.is_completed());
175 /// INIT.call_once(|| {
176 /// assert!(!INIT.is_completed());
177 /// });
178 /// assert!(INIT.is_completed());
179 /// assert!(Once::new_completed().is_completed());
180 /// ```
181 ///
182 /// A poisoned [`Once`] has not completed successfully:
183 ///
184 /// ```
185 /// use parking_lot::Once;
186 /// use std::thread;
187 ///
188 /// static INIT: Once = Once::new();
189 ///
190 /// let handle = thread::spawn(|| {
191 /// INIT.call_once(|| panic!());
192 /// });
193 /// assert!(handle.join().is_err());
194 /// assert!(!INIT.is_completed());
195 /// ```
196 #[inline]
197 pub fn is_completed(&self) -> bool {
198 self.0.load(Ordering::Acquire) & DONE_BIT != 0
199 }
200
201 /// Blocks the current thread until initialization has completed.
202 ///
203 /// Calling this method from an initialization closure for the same `Once`
204 /// may panic or deadlock.
205 ///
206 /// # Examples
207 ///
208 /// ```
209 /// use parking_lot::Once;
210 /// use std::thread;
211 ///
212 /// static READY: Once = Once::new();
213 ///
214 /// let thread = thread::spawn(|| {
215 /// READY.wait();
216 /// println!("everything is ready");
217 /// });
218 ///
219 /// READY.call_once(|| println!("performing setup"));
220 /// thread.join().unwrap();
221 /// ```
222 ///
223 /// # Panics
224 ///
225 /// If this `Once` has been poisoned because an initialization closure has
226 /// panicked, this method will also panic. Use
227 /// [`wait_force`](Self::wait_force) if this behavior is not desired.
228 #[inline]
229 pub fn wait(&self) {
230 if !self.is_completed() {
231 self.wait_slow(false);
232 }
233 }
234
235 /// Blocks the current thread until initialization has completed, ignoring
236 /// poisoning.
237 ///
238 /// If this `Once` has been poisoned, this function blocks until it becomes
239 /// completed, unlike [`Once::wait`], which panics in this case.
240 ///
241 /// Calling this method from an initialization closure for the same `Once`
242 /// may panic or deadlock.
243 #[inline]
244 pub fn wait_force(&self) {
245 if !self.is_completed() {
246 self.wait_slow(true);
247 }
248 }
249
250 /// Performs an initialization routine once and only once. The given closure
251 /// will be executed if this is the first time `call_once` has been called,
252 /// and otherwise the routine will *not* be invoked.
253 ///
254 /// This method will block the calling thread if another initialization
255 /// routine is currently running.
256 ///
257 /// When this function returns, the `Once` is in the completed state. Unless
258 /// it was created with [`new_completed`](Self::new_completed), some
259 /// initialization has run and completed, though it might not be the closure
260 /// specified. Any memory writes performed by the executed closure can be
261 /// reliably observed after this function returns; there is a happens-before
262 /// relation between the closure and code executing after the return.
263 ///
264 /// If the given closure recursively invokes `call_once` on the same `Once`
265 /// instance, the exact behavior is not specified: allowed outcomes are a
266 /// panic or a deadlock.
267 ///
268 /// # Examples
269 ///
270 /// ```
271 /// use parking_lot::Once;
272 ///
273 /// static mut VAL: usize = 0;
274 /// static INIT: Once = Once::new();
275 ///
276 /// // Accessing a `static mut` is unsafe much of the time, but if we do so
277 /// // in a synchronized fashion (e.g. write once or read all) then we're
278 /// // good to go!
279 /// //
280 /// // This function will only call `expensive_computation` once, and will
281 /// // otherwise always return the value returned from the first invocation.
282 /// fn get_cached_val() -> usize {
283 /// unsafe {
284 /// INIT.call_once(|| {
285 /// VAL = expensive_computation();
286 /// });
287 /// VAL
288 /// }
289 /// }
290 ///
291 /// fn expensive_computation() -> usize {
292 /// // ...
293 /// # 2
294 /// }
295 /// ```
296 ///
297 /// # Panics
298 ///
299 /// The closure `f` will only be executed once even if this is called
300 /// concurrently amongst many threads. If that closure panics, however, then
301 /// it will *poison* this `Once` instance, causing all future invocations of
302 /// `call_once` to also panic.
303 #[inline]
304 pub fn call_once<F>(&self, f: F)
305 where
306 F: FnOnce(),
307 {
308 if self.0.load(Ordering::Acquire) == DONE_BIT {
309 return;
310 }
311
312 let mut f = Some(f);
313 self.call_once_slow(false, &mut |_| {
314 let f = f.take();
315 unsafe { f.unwrap_unchecked()() }
316 });
317 }
318
319 /// Performs the same function as [`call_once`](Self::call_once) except it
320 /// ignores poisoning.
321 ///
322 /// Unlike [`call_once`](Self::call_once), if this `Once` has been poisoned
323 /// by a previous initialization panic, this function will still invoke the
324 /// closure `f` instead of immediately panicking. If `f` panics, the `Once`
325 /// remains poisoned. If `f` does not panic, the `Once` is no longer
326 /// poisoned and all future calls to `call_once` or `call_once_force` are
327 /// no-ops.
328 ///
329 /// The closure `f` is passed a [`OnceState`] which can be used to query the
330 /// poison status of this `Once`.
331 ///
332 /// If the given closure recursively invokes `call_once` or
333 /// `call_once_force` on the same `Once` instance, the exact behavior is not
334 /// specified: allowed outcomes are a panic or a deadlock.
335 ///
336 /// # Examples
337 ///
338 /// ```
339 /// use parking_lot::Once;
340 /// use std::thread;
341 ///
342 /// static INIT: Once = Once::new();
343 ///
344 /// // Poison the once.
345 /// let handle = thread::spawn(|| {
346 /// INIT.call_once(|| panic!());
347 /// });
348 /// assert!(handle.join().is_err());
349 ///
350 /// // Poisoning propagates.
351 /// let handle = thread::spawn(|| {
352 /// INIT.call_once(|| {});
353 /// });
354 /// assert!(handle.join().is_err());
355 ///
356 /// // call_once_force still runs and clears the poisoned state.
357 /// INIT.call_once_force(|state| {
358 /// assert!(state.is_poisoned());
359 /// });
360 ///
361 /// // Once initialization succeeds, future calls are no-ops.
362 /// INIT.call_once(|| {});
363 /// ```
364 #[inline]
365 pub fn call_once_force<F>(&self, f: F)
366 where
367 F: FnOnce(OnceState),
368 {
369 if self.0.load(Ordering::Acquire) == DONE_BIT {
370 return;
371 }
372
373 let mut f = Some(f);
374 self.call_once_slow(true, &mut |state| {
375 let f = f.take();
376 unsafe { f.unwrap_unchecked()(state) }
377 });
378 }
379
380 #[cold]
381 fn wait_slow(&self, ignore_poison: bool) {
382 let mut spinwait = SpinWait::new();
383 let mut state = self.0.load(Ordering::Relaxed);
384 loop {
385 if state & DONE_BIT != 0 {
386 // Synchronize with the initialization routine.
387 fence(Ordering::Acquire);
388 return;
389 }
390
391 if state & POISON_BIT != 0 && !ignore_poison {
392 fence(Ordering::Acquire);
393 panic!("Once instance has previously been poisoned");
394 }
395
396 // Only spin while an initialization routine is actively running.
397 if state & LOCKED_BIT != 0 && state & PARKED_BIT == 0 && spinwait.spin() {
398 state = self.0.load(Ordering::Relaxed);
399 continue;
400 }
401
402 // Register that a thread may be parked. `try_update` rechecks the
403 // terminal states on every retry so we cannot miss completion or
404 // poisoning while setting PARKED_BIT.
405 match self
406 .0
407 .try_update(Ordering::Relaxed, Ordering::Relaxed, |state| {
408 if state & DONE_BIT != 0 || (state & POISON_BIT != 0 && !ignore_poison) {
409 None
410 } else {
411 Some(state | PARKED_BIT)
412 }
413 }) {
414 Ok(_) => {}
415 Err(x) => {
416 state = x;
417 continue;
418 }
419 }
420
421 let addr = core::ptr::from_ref(self).addr();
422 let validate = || {
423 let state = self.0.load(Ordering::Relaxed);
424 state & PARKED_BIT != 0
425 && state & DONE_BIT == 0
426 && (ignore_poison || state & POISON_BIT == 0)
427 };
428 let before_sleep = || {};
429 let timed_out = |_, _| unreachable!();
430 // SAFETY:
431 // * `addr` is an address we control.
432 // * `validate` does not panic or call into `parking_lot`.
433 // * `before_sleep` does not call `park` or panic.
434 // * `timed_out` cannot be called because no timeout is specified.
435 unsafe {
436 parking_lot_core::park(
437 addr,
438 validate,
439 before_sleep,
440 timed_out,
441 DEFAULT_PARK_TOKEN,
442 None,
443 );
444 }
445
446 spinwait.reset();
447 state = self.0.load(Ordering::Relaxed);
448 }
449 }
450
451 // This is a non-generic function to reduce the monomorphization cost of
452 // using `call_once` (this isn't exactly a trivial or small implementation).
453 //
454 // Additionally, this is tagged with `#[cold]` as it should indeed be cold
455 // and it helps let LLVM know that calls to this function should be off the
456 // fast path. Essentially, this should help generate more straight line code
457 // in LLVM.
458 //
459 // Finally, this takes an `FnMut` instead of a `FnOnce` because there's
460 // currently no way to take an `FnOnce` and call it via virtual dispatch
461 // without some allocation overhead.
462 #[cold]
463 fn call_once_slow(&self, ignore_poison: bool, f: &mut dyn FnMut(OnceState)) {
464 let mut spinwait = SpinWait::new();
465 let mut state = self.0.load(Ordering::Relaxed);
466 loop {
467 // If another thread called the closure, we're done
468 if state & DONE_BIT != 0 {
469 // An acquire fence is needed here since we didn't load the
470 // state with Ordering::Acquire.
471 fence(Ordering::Acquire);
472 return;
473 }
474
475 // If the state has been poisoned and we aren't forcing, then panic
476 if state & POISON_BIT != 0 && !ignore_poison {
477 // Need the fence here as well for the same reason
478 fence(Ordering::Acquire);
479 panic!("Once instance has previously been poisoned");
480 }
481
482 // Grab the lock if it isn't locked, even if there is a queue on it.
483 // We also clear the poison bit since we are going to try running
484 // the closure again.
485 if state & LOCKED_BIT == 0 {
486 match self.0.compare_exchange_weak(
487 state,
488 (state | LOCKED_BIT) & !POISON_BIT,
489 Ordering::Acquire,
490 Ordering::Relaxed,
491 ) {
492 Ok(_) => break,
493 Err(x) => state = x,
494 }
495 continue;
496 }
497
498 // If there is no queue, try spinning a few times
499 if state & PARKED_BIT == 0 && spinwait.spin() {
500 state = self.0.load(Ordering::Relaxed);
501 continue;
502 }
503
504 // Set the parked bit
505 if state & PARKED_BIT == 0
506 && let Err(x) = self.0.compare_exchange_weak(
507 state,
508 state | PARKED_BIT,
509 Ordering::Relaxed,
510 Ordering::Relaxed,
511 )
512 {
513 state = x;
514 continue;
515 }
516
517 // Park our thread until we are woken up by the thread that owns the
518 // lock.
519 let addr = core::ptr::from_ref(self).addr();
520 let validate = || self.0.load(Ordering::Relaxed) == LOCKED_BIT | PARKED_BIT;
521 let before_sleep = || {};
522 let timed_out = |_, _| unreachable!();
523 unsafe {
524 parking_lot_core::park(
525 addr,
526 validate,
527 before_sleep,
528 timed_out,
529 DEFAULT_PARK_TOKEN,
530 None,
531 );
532 }
533
534 // Loop back and check if the done bit was set
535 spinwait.reset();
536 state = self.0.load(Ordering::Relaxed);
537 }
538
539 struct PanicGuard<'a>(&'a Once);
540 impl<'a> Drop for PanicGuard<'a> {
541 fn drop(&mut self) {
542 // Stop recording ownership, mark the state as poisoned,
543 // unlock it and unpark all threads.
544 let once = self.0;
545 unsafe { deadlock::release_resource(core::ptr::from_ref(once).addr()) };
546 let state = once.0.swap(POISON_BIT, Ordering::Release);
547 if state & PARKED_BIT != 0 {
548 let addr = core::ptr::from_ref(once).addr();
549 unsafe {
550 parking_lot_core::unpark_all(addr, DEFAULT_UNPARK_TOKEN);
551 }
552 }
553 }
554 }
555
556 // At this point we have the lock, so record its ownership and run the
557 // closure. Make sure we properly clean up if the closure panics.
558 unsafe { deadlock::acquire_resource(core::ptr::from_ref(self).addr()) };
559 let guard = PanicGuard(self);
560 let once_state = if state & POISON_BIT != 0 {
561 OnceState::Poisoned
562 } else {
563 OnceState::New
564 };
565 f(once_state);
566 unsafe { deadlock::release_resource(core::ptr::from_ref(self).addr()) };
567 mem::forget(guard);
568
569 // Now unlock the state, set the done bit and unpark all threads
570 let state = self.0.swap(DONE_BIT, Ordering::Release);
571 if state & PARKED_BIT != 0 {
572 let addr = core::ptr::from_ref(self).addr();
573 unsafe {
574 parking_lot_core::unpark_all(addr, DEFAULT_UNPARK_TOKEN);
575 }
576 }
577 }
578}
579
580impl Default for Once {
581 #[inline]
582 fn default() -> Once {
583 Once::new()
584 }
585}
586
587impl fmt::Debug for Once {
588 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
589 f.debug_struct("Once")
590 .field("state", &self.state())
591 .finish()
592 }
593}
594
595#[cfg(test)]
596mod tests {
597 use super::PARKED_BIT;
598 use crate::Once;
599 use std::panic;
600 use std::sync::Arc;
601 use std::sync::atomic::{AtomicUsize, Ordering};
602 use std::sync::mpsc::channel;
603 use std::thread;
604
605 #[test]
606 fn smoke_once() {
607 static O: Once = Once::new();
608 let mut a = 0;
609 O.call_once(|| a += 1);
610 assert_eq!(a, 1);
611 O.call_once(|| a += 1);
612 assert_eq!(a, 1);
613 }
614
615 #[test]
616 fn wait_for_initialization() {
617 let once = Arc::new(Once::new());
618 let value = Arc::new(AtomicUsize::new(0));
619 let waiter = {
620 let once = Arc::clone(&once);
621 let value = Arc::clone(&value);
622 thread::spawn(move || {
623 once.wait();
624 assert_eq!(value.load(Ordering::Relaxed), 1);
625 })
626 };
627
628 while once.0.load(Ordering::Relaxed) & PARKED_BIT == 0 {
629 thread::yield_now();
630 }
631 once.call_once(|| value.store(1, Ordering::Relaxed));
632 waiter.join().unwrap();
633 assert!(once.is_completed());
634 }
635
636 #[test]
637 fn wait_propagates_poison() {
638 let once = Once::new();
639 assert!(panic::catch_unwind(|| once.call_once(|| panic!())).is_err());
640 assert!(panic::catch_unwind(|| once.wait()).is_err());
641 }
642
643 #[test]
644 fn wait_force_ignores_poison() {
645 let once = Arc::new(Once::new());
646 assert!(panic::catch_unwind(|| once.call_once(|| panic!())).is_err());
647
648 let waiter = {
649 let once = Arc::clone(&once);
650 thread::spawn(move || once.wait_force())
651 };
652 while once.0.load(Ordering::Relaxed) & PARKED_BIT == 0 {
653 thread::yield_now();
654 }
655 once.call_once_force(|state| assert!(state.is_poisoned()));
656 waiter.join().unwrap();
657 assert!(once.is_completed());
658 }
659
660 #[test]
661 fn stampede_once() {
662 static O: Once = Once::new();
663 static mut RUN: bool = false;
664
665 let (tx, rx) = channel();
666 for _ in 0..10 {
667 let tx = tx.clone();
668 thread::spawn(move || {
669 for _ in 0..4 {
670 thread::yield_now()
671 }
672 unsafe {
673 O.call_once(|| {
674 assert!(!RUN);
675 RUN = true;
676 });
677 assert!(RUN);
678 }
679 tx.send(()).unwrap();
680 });
681 }
682
683 unsafe {
684 O.call_once(|| {
685 assert!(!RUN);
686 RUN = true;
687 });
688 assert!(RUN);
689 }
690
691 for _ in 0..10 {
692 rx.recv().unwrap();
693 }
694 }
695
696 #[test]
697 fn poison_bad() {
698 static O: Once = Once::new();
699
700 // poison the once
701 let t = panic::catch_unwind(|| {
702 O.call_once(|| panic!());
703 });
704 assert!(t.is_err());
705
706 // poisoning propagates
707 let t = panic::catch_unwind(|| {
708 O.call_once(|| {});
709 });
710 assert!(t.is_err());
711
712 // we can subvert poisoning, however
713 let mut called = false;
714 O.call_once_force(|p| {
715 called = true;
716 assert!(p.poisoned())
717 });
718 assert!(called);
719
720 // once any success happens, we stop propagating the poison
721 O.call_once(|| {});
722 }
723
724 #[test]
725 fn wait_for_force_to_finish() {
726 static O: Once = Once::new();
727
728 // poison the once
729 let t = panic::catch_unwind(|| {
730 O.call_once(|| panic!());
731 });
732 assert!(t.is_err());
733
734 // make sure someone's waiting inside the once via a force
735 let (tx1, rx1) = channel();
736 let (tx2, rx2) = channel();
737 let t1 = thread::spawn(move || {
738 O.call_once_force(|p| {
739 assert!(p.poisoned());
740 tx1.send(()).unwrap();
741 rx2.recv().unwrap();
742 });
743 });
744
745 rx1.recv().unwrap();
746
747 // put another waiter on the once
748 let t2 = thread::spawn(|| {
749 let mut called = false;
750 O.call_once(|| {
751 called = true;
752 });
753 assert!(!called);
754 });
755
756 tx2.send(()).unwrap();
757
758 assert!(t1.join().is_ok());
759 assert!(t2.join().is_ok());
760 }
761
762 #[test]
763 fn test_once_debug() {
764 static O: Once = Once::new();
765
766 assert_eq!(format!("{:?}", O), "Once { state: New }");
767 }
768
769 #[test]
770 fn new_completed_is_done() {
771 use crate::OnceState;
772
773 static O: Once = Once::new_completed();
774 assert_eq!(O.state(), OnceState::Done);
775 assert!(O.state().done());
776 assert!(!O.state().poisoned());
777
778 let mut called = false;
779 O.call_once(|| called = true);
780 assert!(!called);
781 assert_eq!(O.state(), OnceState::Done);
782 }
783
784 #[test]
785 fn new_default_is_new() {
786 // Sanity check that the default constructor is unchanged.
787 static O: Once = Once::new();
788 let mut called = false;
789 O.call_once(|| called = true);
790 assert!(called);
791 }
792}