use std::time::Duration;
use crate::concurrent::atomics::cpu_pause;
use crate::utils::types::Moment;
pub trait Strategy {
fn idle_opt(&self, work_count: i32);
fn idle(&self);
fn reset(&self);
}
pub trait StrategyMut {
fn idle_opt(&mut self, work_count: i32);
fn idle(&mut self);
fn reset(&mut self);
}
const BACK_OFF_STATE_NOT_IDLE: u8 = 0;
const BACK_OFF_STATE_SPINNING: u8 = 1;
const BACK_OFF_STATE_YIELDING: u8 = 2;
const BACK_OFF_STATE_PARKING: u8 = 3;
pub struct BackOffIdleStrategy {
state: u8,
spins: i32,
max_spins: i32,
yields: i32,
max_yields: i32,
park_period_ns: u64,
min_park_period_ns: u64,
max_park_period_ns: u64,
}
impl StrategyMut for BackOffIdleStrategy {
fn idle_opt(&mut self, work_count: i32) {
if work_count > 0 {
self.reset();
} else {
self.idle();
}
}
fn idle(&mut self) {
match self.state {
BACK_OFF_STATE_NOT_IDLE => {
self.state = BACK_OFF_STATE_SPINNING;
self.spins += 1;
},
BACK_OFF_STATE_SPINNING => {
cpu_pause();
self.spins += 1;
if self.spins > self.max_spins {
self.state = BACK_OFF_STATE_YIELDING;
self.yields = 0;
}
},
BACK_OFF_STATE_YIELDING => {
self.yields += 1;
if self.yields > self.max_yields {
self.state = BACK_OFF_STATE_PARKING;
self.park_period_ns = self.min_park_period_ns;
} else {
std::thread::yield_now();
}
},
BACK_OFF_STATE_PARKING => {},
_ => {
std::thread::sleep(Duration::from_nanos(self.park_period_ns));
self.park_period_ns = std::cmp::min(self.park_period_ns * 2, self.max_park_period_ns);
},
}
}
fn reset(&mut self) {
self.spins = 0;
self.yields = 0;
self.park_period_ns = self.min_park_period_ns;
self.state = BACK_OFF_STATE_NOT_IDLE;
}
}
#[derive(Default)]
pub struct BusySpinIdleStrategy {}
impl BusySpinIdleStrategy {
fn pause() {
cpu_pause();
}
}
impl Strategy for BusySpinIdleStrategy {
fn idle_opt(&self, work_count: i32) {
if work_count > 0 {
return;
}
Self::pause();
}
fn idle(&self) {
Self::pause();
}
fn reset(&self) {}
}
pub struct NoOpIdleStrategy {}
impl Strategy for NoOpIdleStrategy {
fn idle_opt(&self, _work_count: i32) {}
fn idle(&self) {}
fn reset(&self) {}
}
pub struct SleepingIdleStrategy {
duration: Moment,
}
impl SleepingIdleStrategy {
pub fn new(duration: Moment) -> Self {
Self { duration }
}
}
impl Strategy for SleepingIdleStrategy {
fn idle_opt(&self, work_count: i32) {
if 0 == work_count {
std::thread::sleep(Duration::from_millis(self.duration));
}
}
fn idle(&self) {
std::thread::sleep(Duration::from_millis(self.duration));
}
fn reset(&self) {}
}
pub struct YieldingIdleStrategy {}
impl Strategy for YieldingIdleStrategy {
fn idle_opt(&self, work_count: i32) {
if 0 == work_count {
return;
}
std::thread::yield_now();
}
fn idle(&self) {
std::thread::yield_now();
}
fn reset(&self) {}
}