flize/
backoff.rs

1// LICENSE NOTICE: Most of this code has been copied from the crossbeam repository with the MIT license.
2
3use std::cell::Cell;
4use std::sync::atomic;
5
6const SPIN_LIMIT: u32 = 6;
7const YIELD_LIMIT: u32 = 10;
8
9pub struct Backoff {
10    step: Cell<u32>,
11}
12
13impl Backoff {
14    pub fn new() -> Self {
15        Self { step: Cell::new(0) }
16    }
17
18    pub fn reset(&self) {
19        self.step.set(0);
20    }
21
22    pub fn spin(&self) {
23        for _ in 0..1 << self.step.get().min(SPIN_LIMIT) {
24            atomic::spin_loop_hint();
25        }
26
27        if self.step.get() <= SPIN_LIMIT {
28            self.step.set(self.step.get() + 1);
29        }
30    }
31
32    pub fn snooze(&self) {
33        if self.step.get() <= SPIN_LIMIT {
34            for _ in 0..1 << self.step.get() {
35                atomic::spin_loop_hint();
36            }
37        } else {
38            #[cfg(not(feature = "std"))]
39            for _ in 0..1 << self.step.get() {
40                atomic::spin_loop_hint();
41            }
42
43            #[cfg(feature = "std")]
44            ::std::thread::yield_now();
45        }
46
47        if self.step.get() <= YIELD_LIMIT {
48            self.step.set(self.step.get() + 1);
49        }
50    }
51
52    pub fn is_completed(&self) -> bool {
53        self.step.get() > YIELD_LIMIT
54    }
55}
56
57impl Default for Backoff {
58    fn default() -> Self {
59        Self::new()
60    }
61}