use crate::wait_strategies::WakeupNotifier;
use crossbeam_utils::CachePadded;
use std::sync::{
atomic::{AtomicI64, Ordering},
Arc,
};
#[derive(Clone, Debug)]
pub(crate) struct DependentSequence(Arc<CachePadded<AtomicI64>>);
impl DependentSequence {
pub(crate) fn new() -> Self {
Self::with_value(-1)
}
pub(crate) fn with_value(v: i64) -> Self {
Self(Arc::new(CachePadded::new(AtomicI64::new(v))))
}
pub(crate) fn get(&self) -> i64 {
self.0.load(Ordering::Acquire)
}
pub(crate) fn set(&self, v: i64) {
self.0.store(v, Ordering::Release);
}
pub(crate) fn compare_and_set(&self, current: i64, new: i64) -> Result<i64, i64> {
self.0
.compare_exchange(current, new, Ordering::AcqRel, Ordering::Acquire)
}
}
impl Default for DependentSequence {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone)]
pub struct GatedSequence<N> {
inner: DependentSequence,
notifier: N,
}
impl<N> GatedSequence<N> {
pub(crate) fn new(inner: DependentSequence, notifier: N) -> Self {
Self { inner, notifier }
}
pub fn get(&self) -> i64 {
self.inner.get()
}
pub(crate) fn dependent(&self) -> DependentSequence {
self.inner.clone()
}
}
impl<N: WakeupNotifier> GatedSequence<N> {
pub fn set(&self, v: i64) {
self.inner.set(v);
self.notifier.wake();
}
pub fn compare_and_set(&self, current: i64, new: i64) -> Result<i64, i64> {
let result = self.inner.compare_and_set(current, new);
if result.is_ok() {
self.notifier.wake();
}
result
}
}