Skip to main content

parking_lot_core/
spinwait.rs

1use crate::thread_parker;
2use core::hint::spin_loop;
3
4// Wastes some CPU time for the given number of iterations,
5// using a hint to indicate to the CPU that we are spinning.
6#[inline]
7fn cpu_relax(iterations: u32) {
8    for _ in 0..iterations {
9        spin_loop()
10    }
11}
12
13/// A counter used to perform exponential backoff in spin loops.
14#[derive(#[automatically_derived]impl ::core::default::Default for SpinWait {
    #[inline]
    fn default() -> Self {
        SpinWait { counter: ::core::default::Default::default() }
    }
}Default)]
15pub struct SpinWait {
16    counter: u32,
17}
18
19impl SpinWait {
20    /// Creates a new `SpinWait`.
21    #[inline]
22    pub const fn new() -> Self {
23        Self { counter: 0 }
24    }
25
26    /// Resets a `SpinWait` to its initial state.
27    #[inline]
28    pub const fn reset(&mut self) {
29        self.counter = 0;
30    }
31
32    /// Spins until the sleep threshold has been reached.
33    ///
34    /// This function returns `false` if the sleep threshold has been reached,
35    /// at which point further spinning has diminishing returns and the thread
36    /// should be parked instead.
37    ///
38    /// The spin strategy will initially use a CPU-bound loop but will fall back
39    /// to yielding the CPU to the OS after a few iterations.
40    #[inline]
41    pub fn spin(&mut self) -> bool {
42        if self.counter >= 10 {
43            return false;
44        }
45        self.counter += 1;
46        if self.counter <= 3 {
47            cpu_relax(1 << (self.counter - 1));
48        } else {
49            thread_parker::thread_yield();
50        }
51        true
52    }
53
54    /// Spins without yielding the thread to the OS.
55    ///
56    /// Instead, the backoff is simply capped at a maximum value. This can be
57    /// used to improve throughput in `compare_exchange` loops that have high
58    /// contention.
59    #[inline]
60    pub fn spin_no_yield(&mut self) {
61        self.counter += 1;
62        if self.counter > 10 {
63            self.counter = 10;
64        }
65        cpu_relax(1 << (self.counter - 1));
66    }
67}