use crate::primitive::sync::atomic;
use core::cell::Cell;
use core::fmt;
const SPIN_LIMIT: u32 = 6;
const YIELD_LIMIT: u32 = 10;
pub struct Backoff {
step: Cell<u32>,
}
impl Backoff {
#[inline]
pub fn new() -> Self {
Backoff { step: Cell::new(0) }
}
#[inline]
pub fn reset(&self) {
self.step.set(0);
}
#[inline]
pub fn spin(&self) {
for _ in 0..1 << self.step.get().min(SPIN_LIMIT) {
#[allow(deprecated)]
atomic::spin_loop_hint();
}
if self.step.get() <= SPIN_LIMIT {
self.step.set(self.step.get() + 1);
}
}
#[inline]
pub fn snooze(&self) {
if self.step.get() <= SPIN_LIMIT {
for _ in 0..1 << self.step.get() {
#[allow(deprecated)]
atomic::spin_loop_hint();
}
} else {
#[cfg(not(feature = "std"))]
for _ in 0..1 << self.step.get() {
#[allow(deprecated)]
atomic::spin_loop_hint();
}
#[cfg(feature = "std")]
::std::thread::yield_now();
}
if self.step.get() <= YIELD_LIMIT {
self.step.set(self.step.get() + 1);
}
}
#[inline]
pub fn is_completed(&self) -> bool {
self.step.get() > YIELD_LIMIT
}
}
impl fmt::Debug for Backoff {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Backoff")
.field("step", &self.step)
.field("is_completed", &self.is_completed())
.finish()
}
}
impl Default for Backoff {
fn default() -> Backoff {
Backoff::new()
}
}