use core::sync::atomic::{AtomicU64, Ordering};
static GLOBAL_ERA: AtomicU64 = AtomicU64::new(0);
thread_local! {
static ALLOC_COUNTER: core::cell::Cell<u32> = const { core::cell::Cell::new(0) };
}
const ERA_ADVANCE_THRESHOLD: u32 = 1 << 8;
#[allow(dead_code)]
pub(crate) const STALL_THRESHOLD: isize = 1 << 15;
#[inline]
pub fn current_era() -> u64 {
GLOBAL_ERA.load(Ordering::Acquire)
}
#[inline]
pub fn maybe_advance_era() {
ALLOC_COUNTER.with(|counter| {
let count = counter.get();
counter.set(count.wrapping_add(1));
if count % ERA_ADVANCE_THRESHOLD == 0 {
GLOBAL_ERA.fetch_add(1, Ordering::Release);
}
});
}
#[derive(Debug, Clone, Copy)]
pub struct BirthEra(u64);
impl BirthEra {
#[inline]
pub fn new() -> Self {
maybe_advance_era();
Self(current_era())
}
#[inline]
pub fn value(&self) -> u64 {
self.0
}
#[inline]
pub fn is_older_than(&self, other: u64) -> bool {
self.0 < other
}
}
impl Default for BirthEra {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_era_advancement() {
let start = current_era();
for _ in 0..ERA_ADVANCE_THRESHOLD * 2 {
maybe_advance_era();
}
let end = current_era();
assert!(end > start, "Era should advance");
}
#[test]
fn test_birth_era() {
let era1 = BirthEra::new();
for _ in 0..ERA_ADVANCE_THRESHOLD {
maybe_advance_era();
}
let era2 = BirthEra::new();
assert!(era1.is_older_than(era2.value()));
}
}