use core::task::RawWaker;
use core::task::RawWakerVTable;
use core::task::Waker;
use crate::platform::*;
const IDLE: u32 = 0;
const WAIT: u32 = 1;
const WAKE: u32 = 2;
pub struct Blocker {
state: AtomicU32,
#[cfg(feature = "shuttle")]
mutex: Mutex<()>,
#[cfg(feature = "shuttle")]
condvar: Condvar,
}
impl Blocker {
pub fn new() -> Self {
Self {
state: AtomicU32::new(IDLE),
#[cfg(feature = "shuttle")]
mutex: Mutex::new(()),
#[cfg(feature = "shuttle")]
condvar: Condvar::new(),
}
}
pub unsafe fn as_waker(&self) -> Waker {
let this: *const Self = self;
let raw_waker = RawWaker::new(this.cast::<()>(), &RAW_WAKER_VTABLE);
unsafe { Waker::from_raw(raw_waker) }
}
#[inline]
pub fn would_block(&self) -> bool {
self.state.load(Ordering::Relaxed) != WAKE
}
#[inline]
pub fn block(&self) {
let state = self.state.swap(WAIT, Ordering::Relaxed);
if state != WAKE {
#[cfg(not(feature = "shuttle"))]
atomic_wait::wait(&self.state, state);
#[cfg(feature = "shuttle")]
let _ = self.condvar.wait(self.mutex.lock().unwrap());
}
self.state.store(IDLE, Ordering::Relaxed);
}
}
const RAW_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
#[inline(always)]
|ptr| RawWaker::new(ptr, &RAW_WAKER_VTABLE),
wake,
wake,
|_| {},
);
fn wake(this: *const ()) {
let blocker = unsafe { &*this.cast::<Blocker>() };
if blocker.state.swap(WAKE, Ordering::Relaxed) == WAIT {
#[cfg(not(feature = "shuttle"))]
atomic_wait::wake_all(&blocker.state);
#[cfg(feature = "shuttle")]
blocker.condvar.notify_all();
}
}