use core::cell::UnsafeCell;
use core::sync::atomic::{AtomicU8};
use core::sync::atomic::Ordering::{Acquire, Release, AcqRel};
use core::task::{self, Waker};
struct AtomicWaker {
state: AtomicU8,
waker: UnsafeCell<Option<Waker>>,
}
const WAITING: u8 = 0;
const REGISTERING: u8 = 0b01;
const WAKING: u8 = 0b10;
impl AtomicWaker {
const fn new() -> Self {
Self {
state: AtomicU8::new(WAITING),
waker: UnsafeCell::new(None),
}
}
fn register(&self, waker: &Waker) {
match self.state.compare_and_swap(WAITING, REGISTERING, Acquire) {
WAITING => {
unsafe {
*self.waker.get() = Some(waker.clone());
let res = self.state.compare_exchange(REGISTERING, WAITING, AcqRel, Acquire);
match res {
Ok(_) => {}
Err(actual) => {
debug_assert_eq!(actual, REGISTERING | WAKING);
let waker = (*self.waker.get()).take().unwrap();
self.state.swap(WAITING, AcqRel);
waker.wake();
}
}
}
}
WAKING => {
waker.wake_by_ref();
}
state => {
debug_assert!(
state == REGISTERING ||
state == REGISTERING | WAKING);
}
}
}
fn is_registered(&self) -> bool {
match self.state.load(Acquire) {
WAITING => unsafe { (*self.waker.get()).is_some() },
state => (state & WAKING) == 0,
}
}
fn wake(&self) {
if let Some(waker) = self.take() {
waker.wake();
}
}
fn take(&self) -> Option<Waker> {
match self.state.fetch_or(WAKING, AcqRel) {
WAITING => {
let waker = unsafe { (*self.waker.get()).take() };
self.state.fetch_and(!WAKING, Release);
waker
}
state => {
debug_assert!(
state == REGISTERING ||
state == REGISTERING | WAKING ||
state == WAKING);
None
}
}
}
}
unsafe impl Send for AtomicWaker {}
unsafe impl Sync for AtomicWaker {}
pub struct TimerState {
inner: AtomicWaker,
}
impl TimerState {
pub const fn new() -> Self {
Self {
inner: AtomicWaker::new(),
}
}
#[inline]
pub fn is_done(&self) -> bool {
!self.inner.is_registered()
}
#[inline]
pub fn register(&self, waker: &task::Waker) {
self.inner.register(waker)
}
#[inline]
pub fn wake(&self) {
self.inner.wake();
}
}