use core::{task};
use core::cell::UnsafeCell;
use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
#[cold]
fn should_not_clone(_: *const()) -> task::RawWaker {
panic!("Impossible Waker Clone");
}
mod plain_fn {
use core::{task, mem};
static VTABLE: task::RawWakerVTable = task::RawWakerVTable::new(super::should_not_clone, action, action, super::noop::action);
unsafe fn action(callback: *const ()) {
let func: fn() = mem::transmute(callback);
func()
}
pub fn waker(data: fn()) -> task::Waker {
unsafe {
task::Waker::from_raw(task::RawWaker::new(data as *const (), &VTABLE))
}
}
}
mod noop {
use core::{ptr, task};
static VTABLE: task::RawWakerVTable = task::RawWakerVTable::new(super::should_not_clone, action, action, action);
pub fn action(_: *const ()) {
}
#[inline(always)]
pub fn waker() -> task::Waker {
unsafe {
task::Waker::from_raw(task::RawWaker::new(ptr::null(), &VTABLE))
}
}
}
const WAITING: u8 = 0;
const REGISTERING: u8 = 0b01;
const WAKING: u8 = 0b10;
#[doc(hidden)]
pub struct AtomicWaker {
state: AtomicU8,
waker: UnsafeCell<task::Waker>,
}
impl AtomicWaker {
fn new() -> Self {
Self {
state: AtomicU8::new(WAITING),
waker: UnsafeCell::new(noop::waker()),
}
}
fn register_owned(&self, waker: task::Waker) {
match self.state.compare_and_swap(WAITING, REGISTERING, Ordering::Acquire) {
WAITING => {
unsafe {
*self.waker.get() = waker;
let res = self.state.compare_exchange(REGISTERING, WAITING, Ordering::AcqRel, Ordering::Acquire);
match res {
Ok(_) => {}
Err(actual) => {
debug_assert_eq!(actual, REGISTERING | WAKING);
(*self.waker.get()).wake_by_ref();
self.state.swap(WAITING, Ordering::AcqRel);
}
}
}
}
WAKING => {
waker.wake();
}
state => debug_assert!(state == REGISTERING || state == REGISTERING | WAKING),
}
}
fn register(&self, waker: &task::Waker) {
match self.state.compare_and_swap(WAITING, REGISTERING, Ordering::Acquire) {
WAITING => {
unsafe {
*self.waker.get() = waker.clone();
let res = self.state.compare_exchange(REGISTERING, WAITING, Ordering::AcqRel, Ordering::Acquire);
match res {
Ok(_) => {}
Err(actual) => {
debug_assert_eq!(actual, REGISTERING | WAKING);
(*self.waker.get()).wake_by_ref();
self.state.swap(WAITING, Ordering::AcqRel);
}
}
}
}
WAKING => {
waker.wake_by_ref();
}
state => {
debug_assert!(
state == REGISTERING ||
state == REGISTERING | WAKING);
}
}
}
fn wake(&self) {
match self.state.fetch_or(WAKING, Ordering::AcqRel) {
WAITING => {
unsafe { (*self.waker.get()).wake_by_ref() };
self.state.fetch_and(!WAKING, Ordering::Release);
}
state => {
debug_assert!(
state == REGISTERING ||
state == REGISTERING | WAKING ||
state == WAKING);
}
}
}
}
unsafe impl Send for AtomicWaker {}
unsafe impl Sync for AtomicWaker {}
pub struct TimerState {
woken: AtomicBool,
inner: AtomicWaker,
}
impl TimerState {
pub fn new() -> Self {
Self {
woken: AtomicBool::new(false),
inner: AtomicWaker::new(),
}
}
#[inline]
pub fn is_done(&self) -> bool {
self.woken.load(Ordering::Acquire)
}
#[inline]
pub fn reset(&self) {
self.woken.store(false, Ordering::Release);
}
#[inline]
pub fn cancel(&self) {
self.woken.store(true, Ordering::Release);
}
#[inline]
pub fn register<C: Callback>(&self, cb: C) {
cb.register(&self.inner);
}
#[inline]
pub(crate) fn wake(&self) {
if !self.woken.compare_and_swap(false, true, Ordering::SeqCst) {
self.inner.wake();
}
}
}
pub trait Callback {
#[doc(hidden)]
fn register(self, waker: &AtomicWaker);
}
impl<'a> Callback for &'a task::Waker {
#[inline(always)]
fn register(self, waker: &AtomicWaker) {
waker.register(self)
}
}
impl Callback for task::Waker {
#[inline(always)]
fn register(self, waker: &AtomicWaker) {
waker.register_owned(self)
}
}
impl<'a> Callback for fn() {
fn register(self, waker: &AtomicWaker) {
waker.register_owned(plain_fn::waker(self));
}
}