1use crate::cpu_relax;
2
3pub trait WaitStrategy {
15 fn reset(&mut self);
17
18 fn wait(&mut self);
20}
21
22#[derive(Debug, Clone)]
24pub struct SpinWait {
25 spins: u32,
26 spin_limit: u32,
27}
28
29impl Default for SpinWait {
30 fn default() -> Self {
31 Self {
32 spins: 0,
33 spin_limit: 10_000,
34 }
35 }
36}
37
38impl SpinWait {
39 pub const fn new(spin_limit: u32) -> Self {
44 Self {
45 spins: 0,
46 spin_limit,
47 }
48 }
49}
50
51impl WaitStrategy for SpinWait {
52 #[inline]
53 fn reset(&mut self) {
54 self.spins = 0;
55 }
56
57 #[inline]
58 fn wait(&mut self) {
59 cpu_relax();
60 if self.spins < self.spin_limit {
61 self.spins += 1;
62 }
63 }
64}
65
66#[cfg(feature = "std")]
68#[derive(Debug, Clone)]
69pub struct StdBackoff {
70 spins: u32,
71 yields: u32,
72 sleep_us: u64,
73
74 spin_limit: u32,
75 yield_limit: u32,
76 sleep_us_initial: u64,
77 sleep_us_max: u64,
78}
79
80#[cfg(feature = "std")]
82#[derive(Debug, Clone, Default)]
83pub struct YieldWait;
84
85#[cfg(feature = "std")]
86impl YieldWait {
87 pub const fn new() -> Self {
89 Self
90 }
91}
92
93#[cfg(feature = "std")]
94impl WaitStrategy for YieldWait {
95 #[inline]
96 fn reset(&mut self) {}
97
98 #[inline]
99 fn wait(&mut self) {
100 std::thread::yield_now();
101 }
102}
103
104#[cfg(feature = "std")]
105impl StdBackoff {
106 #[inline]
107 pub const fn new(
111 spin_limit: u32,
112 yield_limit: u32,
113 sleep_us_initial: u64,
114 sleep_us_max: u64,
115 ) -> Self {
116 Self {
117 spins: 0,
118 yields: 0,
119 sleep_us: 0,
120 spin_limit,
121 yield_limit,
122 sleep_us_initial,
123 sleep_us_max,
124 }
125 }
126}
127
128#[cfg(feature = "std")]
129impl Default for StdBackoff {
130 fn default() -> Self {
131 Self {
132 spins: 0,
133 yields: 0,
134 sleep_us: 0,
135 spin_limit: 10_000,
136 yield_limit: 1_000,
137 sleep_us_initial: 10,
138 sleep_us_max: 1_000,
139 }
140 }
141}
142
143#[cfg(feature = "std")]
144impl WaitStrategy for StdBackoff {
145 #[inline]
146 fn reset(&mut self) {
147 self.spins = 0;
148 self.yields = 0;
149 self.sleep_us = 0;
150 }
151
152 #[inline]
153 fn wait(&mut self) {
154 if self.spins < self.spin_limit {
155 self.spins += 1;
156 cpu_relax();
157 return;
158 }
159
160 if self.yields < self.yield_limit {
161 self.yields += 1;
162 std::thread::yield_now();
163 return;
164 }
165
166 if self.sleep_us == 0 {
167 self.sleep_us = self.sleep_us_initial;
168 } else {
169 self.sleep_us = (self.sleep_us * 2).min(self.sleep_us_max);
170 }
171
172 std::thread::sleep(std::time::Duration::from_micros(self.sleep_us));
173 }
174}