use crate::macros::conditional_const;
#[cfg(feature = "std")]
use crate::sync::{AtomicU64, Ordering};
#[cfg(feature = "std")]
use core::time::Duration;
#[cfg(feature = "std")]
const DEFAULT_SYNC_THRESHOLD: Duration = Duration::from_nanos(2000000000);
const DEFAULT_RETIRED_THRESHOLD: isize = 1000;
const DEFAULT_HAZARD_POINTER_MULTIPLIER: isize = 2;
#[derive(Debug)]
#[non_exhaustive]
pub enum ReclaimStrategy {
Eager,
TimedCapped(TimedCappedSettings),
Manual,
}
impl ReclaimStrategy {
pub(super) fn should_reclaim(&self, hazard_pointer_count: isize, retired_count: isize) -> bool {
match self {
Self::Eager => true,
Self::TimedCapped(settings) => {
settings.should_reclaim(hazard_pointer_count, retired_count)
}
Self::Manual => false,
}
}
conditional_const!(
pub fn default() -> Self {
Self::TimedCapped(TimedCappedSettings::default())
}
);
}
#[derive(Debug)]
pub struct TimedCappedSettings {
#[cfg(feature = "std")]
last_sync_time: AtomicU64,
#[cfg(feature = "std")]
sync_timeout: Duration,
hazard_pointer_multiplier: isize,
retired_threshold: isize,
}
impl TimedCappedSettings {
#[cfg(feature = "std")]
conditional_const!(
pub fn new_with_timeout(
sync_timeout: Duration,
retired_threshold: isize,
hazard_pointer_multiplier: isize,
) -> Self {
Self {
#[cfg(feature = "std")]
last_sync_time: AtomicU64::new(0),
#[cfg(feature = "std")]
sync_timeout,
retired_threshold,
hazard_pointer_multiplier,
}
}
);
conditional_const!(
pub fn new(retired_threshold: isize, hazard_pointer_multiplier: isize) -> Self {
Self {
#[cfg(feature = "std")]
last_sync_time: AtomicU64::new(0),
#[cfg(feature = "std")]
sync_timeout: DEFAULT_SYNC_THRESHOLD,
retired_threshold,
hazard_pointer_multiplier,
}
}
);
fn should_reclaim(&self, hazard_pointer_count: isize, retired_count: isize) -> bool {
if retired_count >= self.retired_threshold
&& retired_count >= hazard_pointer_count * self.hazard_pointer_multiplier
{
return true;
}
self.check_sync_time()
}
#[cfg(feature = "std")]
fn check_sync_time(&self) -> bool {
use core::convert::TryFrom;
let time = u64::try_from(
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.expect("system time is set to before the epoch")
.as_nanos(),
)
.expect("system time is too far into the future");
let last_sync_time = self.last_sync_time.load(Ordering::Relaxed);
time > last_sync_time
&& self
.last_sync_time
.compare_exchange(
last_sync_time,
time + self.sync_timeout.as_nanos() as u64,
Ordering::Relaxed,
Ordering::Relaxed,
)
.is_ok()
}
#[cfg(not(feature = "std"))]
#[inline(always)]
fn check_sync_time(&self) -> bool {
true
}
conditional_const!(
pub fn default() -> Self {
Self::new(DEFAULT_RETIRED_THRESHOLD, DEFAULT_HAZARD_POINTER_MULTIPLIER)
}
);
#[cfg(feature = "std")]
pub const fn with_timeout(self, sync_timeout: Duration) -> Self {
Self {
sync_timeout,
..self
}
}
pub const fn with_hazard_pointer_multiplier(self, hazard_pointer_multiplier: isize) -> Self {
Self {
hazard_pointer_multiplier,
..self
}
}
pub const fn with_retired_threshold(self, retired_threshold: isize) -> Self {
Self {
retired_threshold,
..self
}
}
}