use crate::is;
use crate::{AtomicOrdering, AtomicU8, AtomicUsize, CacheAlign};
use crate::{MemHedgeError, MemHedgeState};
#[doc = crate::_tags!(mem concurrency atomic)]
#[doc = crate::_doc_meta!{location("sys/mem/cell")}]
#[derive(Debug)]
pub struct MemHedgeCtrl {
epoch: CacheAlign<AtomicUsize>,
logical_index: CacheAlign<AtomicUsize>,
winner: CacheAlign<AtomicUsize>,
state: CacheAlign<AtomicU8>,
}
impl MemHedgeCtrl {
pub const NONE_WINNER: usize = usize::MAX;
pub const fn new() -> Self {
Self {
epoch: CacheAlign::new(AtomicUsize::new(0)),
logical_index: CacheAlign::new(AtomicUsize::new(0)),
winner: CacheAlign::new(AtomicUsize::new(Self::NONE_WINNER)),
state: CacheAlign::new(AtomicU8::new(MemHedgeState::Idle as u8)),
}
}
pub fn epoch(&self) -> usize {
self.epoch.load(AtomicOrdering::Acquire)
}
pub fn logical_index(&self) -> usize {
self.logical_index.load(AtomicOrdering::Acquire)
}
pub fn state(&self) -> MemHedgeState {
let raw = self.state.load(AtomicOrdering::Acquire);
if let Some(state) = MemHedgeState::from_u8(raw) {
state
} else {
debug_assert!(false, "invalid MemHedgeState value: {raw}");
MemHedgeState::Idle
}
}
pub fn winner(&self) -> Option<usize> {
let winner = self.winner.load(AtomicOrdering::Acquire);
is! { winner == Self::NONE_WINNER, None, Some(winner) }
}
pub fn arm(&self, logical_index: usize) -> Result<usize, MemHedgeError> {
let idle = MemHedgeState::Idle.as_u8();
let armed = MemHedgeState::Armed.as_u8();
self.state
.compare_exchange(idle, armed, AtomicOrdering::AcqRel, AtomicOrdering::Acquire)
.map_err(|_| MemHedgeError::Busy)?;
self.logical_index.store(logical_index, AtomicOrdering::Relaxed);
self.winner.store(Self::NONE_WINNER, AtomicOrdering::Relaxed);
Ok(self.epoch.fetch_add(1, AtomicOrdering::Release) + 1)
}
pub fn clear(&self) {
self.logical_index.store(0, AtomicOrdering::Relaxed);
self.winner.store(Self::NONE_WINNER, AtomicOrdering::Relaxed);
self.state.store(MemHedgeState::Idle.as_u8(), AtomicOrdering::Release);
}
pub fn try_claim(&self, replica: usize) -> Result<bool, MemHedgeError> {
is! { self.state() != MemHedgeState::Armed, return Err(MemHedgeError::NotArmed) }
match self.winner.compare_exchange(
Self::NONE_WINNER,
replica,
AtomicOrdering::AcqRel,
AtomicOrdering::Acquire,
) {
Ok(_) => {
self.state.store(MemHedgeState::Claimed.as_u8(), AtomicOrdering::Release);
Ok(true)
}
Err(_) => Ok(false),
}
}
}
impl Default for MemHedgeCtrl {
fn default() -> Self {
Self::new()
}
}