static_init/phase_locker/
spin_wait.rs

1use core::hint;
2// Extracted from parking_lot_core
3//
4#[inline]
5fn cpu_relax(iterations: u32) {
6    for _ in 0..iterations {
7        hint::spin_loop()
8    }
9}
10
11/// A counter used to perform exponential backoff in spin loops.
12#[derive(Default)]
13pub(super) struct SpinWait {
14    counter: u32,
15}
16
17impl SpinWait {
18    /// Creates a new `SpinWait`.
19    #[inline]
20    pub fn new() -> Self {
21        Self::default()
22    }
23
24    /// Resets a `SpinWait` to its initial state.
25    #[inline]
26    #[cfg(not(feature = "spin_loop"))]
27    pub fn reset(&mut self) {
28        self.counter = 0;
29    }
30
31    /// Spins until the sleep threshold has been reached.
32    ///
33    /// This function returns whether the sleep threshold has been reached, at
34    /// which point further spinning has diminishing returns and the thread
35    /// should be parked instead.
36    ///
37    /// The spin strategy will initially use a CPU-bound loop but will fall back
38    /// to yielding the CPU to the OS after a few iterations.
39    #[inline]
40    #[cfg(not(feature = "spin_loop"))]
41    pub fn spin(&mut self) -> bool {
42        if self.counter >= 10
43        /*16*/
44        {
45            return false;
46        }
47        self.counter += 1;
48
49        if self.counter <= 3
50        /*4*/
51        {
52            cpu_relax(1 << self.counter);
53        } else {
54            yield_now();
55        }
56        true
57    }
58
59    /// Spins without yielding the thread to the OS.
60    ///
61    /// Instead, the backoff is simply capped at a maximum value. This can be
62    /// used to improve throughput in `compare_exchange` loops that have high
63    /// contention.
64    #[inline]
65    pub fn spin_no_yield(&mut self) -> bool {
66        self.counter += 1;
67        if self.counter > 10 {
68            self.counter = 10;
69        }
70        cpu_relax(1 << self.counter);
71        true
72    }
73}
74
75#[cfg(all(
76    not(feature = "parking_lot_core"),
77    not(feature = "spin_loop"),
78    any(target_os = "linux", target_os = "android")
79))]
80fn yield_now() {
81    unsafe {
82        libc::sched_yield();
83    }
84}
85#[cfg(all(
86    not(feature = "spin_loop"),
87    not(all(
88        not(feature = "parking_lot_core"),
89        any(target_os = "linux", target_os = "android")
90    ))
91))]
92use std::thread::yield_now;