use std::sync::PoisonError;
use crate::sync::{Arc, AtomicUsize, Condvar, Mutex, Ordering};
pub(super) trait Latch: Sync {
unsafe fn set(this: *const Self);
}
pub(super) struct SpinLatch {
state: AtomicUsize,
}
impl SpinLatch {
pub(super) fn new() -> Self {
Self {
state: AtomicUsize::new(0),
}
}
pub(super) fn probe(&self) -> bool {
self.state.load(Ordering::Acquire) == 1
}
}
impl Latch for SpinLatch {
unsafe fn set(this: *const Self) {
unsafe { (*this).state.store(1, Ordering::Release) };
}
}
pub(super) struct LockLatch {
shared: Arc<(Mutex<bool>, Condvar)>,
}
impl LockLatch {
pub(super) fn new() -> Self {
Self {
shared: Arc::new((Mutex::new(false), Condvar::new())),
}
}
pub(super) fn wait(&self) {
let (lock, cv) = &*self.shared;
let mut set = lock.lock().unwrap_or_else(PoisonError::into_inner);
while !*set {
set = cv.wait(set).unwrap_or_else(PoisonError::into_inner);
}
}
}
impl Latch for LockLatch {
unsafe fn set(this: *const Self) {
let shared = unsafe { Arc::clone(&(*this).shared) };
let (lock, cv) = &*shared;
*lock.lock().unwrap_or_else(PoisonError::into_inner) = true;
cv.notify_all();
}
}