1use 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}