use std::cell::UnsafeCell;
use std::fmt;
use std::ops::Deref;
use std::sync::{
atomic::{AtomicU32, AtomicU8, Ordering},
Arc, Weak,
};
use std::task::*;
use std::thread;
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum WakerState {
Init = 0, Waiting = 1,
Woken = 3,
Closed = 4, Done = 5,
}
#[derive(PartialEq, Debug, Clone, Copy)]
#[repr(u8)]
pub enum WakeResult {
Woken = 0x1, Sent = 0x3, Next = 0x2, Skip = 0x4, }
impl WakeResult {
#[inline(always)]
pub fn is_done(&self) -> bool {
(*self as u8) & (WakeResult::Woken as u8) > 0
}
}
pub struct ArcWaker(Arc<WakerInner>);
impl fmt::Debug for ArcWaker {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl fmt::Debug for WakerInner {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "waker({})", self.get_seq())
}
}
impl Deref for ArcWaker {
type Target = WakerInner;
#[inline]
fn deref(&self) -> &Self::Target {
self.0.as_ref()
}
}
impl ArcWaker {
#[inline(always)]
pub fn new_async(ctx: &Context) -> Self {
Self(Arc::new(WakerInner {
seq: AtomicU32::new(0),
state: AtomicU8::new(WakerState::Init as u8),
waker: UnsafeCell::new(ThinWaker::Async(ctx.waker().clone())),
}))
}
#[inline(always)]
pub fn new_blocking() -> Self {
Self(Arc::new(WakerInner {
seq: AtomicU32::new(0),
state: AtomicU8::new(WakerState::Init as u8),
waker: UnsafeCell::new(ThinWaker::Blocking(thread::current())),
}))
}
}
impl ArcWaker {
#[inline(always)]
pub fn from_arc(inner: Arc<WakerInner>) -> Self {
Self(inner)
}
#[allow(clippy::wrong_self_convention)]
#[inline(always)]
pub fn to_arc(self) -> Arc<WakerInner> {
self.0
}
#[inline(always)]
pub fn weak(&self) -> Weak<WakerInner> {
Arc::downgrade(&self.0)
}
}
#[derive(Debug)]
pub(crate) enum ThinWaker {
Async(Waker),
Blocking(thread::Thread),
}
impl ThinWaker {
#[inline(always)]
pub fn wake_by_ref(&self) {
match self {
Self::Async(w) => w.wake_by_ref(),
Self::Blocking(th) => th.unpark(),
}
}
#[allow(dead_code)]
#[inline(always)]
pub fn wake(self) {
match self {
Self::Async(w) => w.wake(),
Self::Blocking(th) => th.unpark(),
}
}
#[inline(always)]
pub fn will_wake(&self, ctx: &mut Context) -> bool {
if let Self::Async(_waker) = self {
_waker.will_wake(ctx.waker())
} else {
unreachable!();
}
}
}
pub struct WakerInner {
state: AtomicU8,
seq: AtomicU32,
waker: UnsafeCell<ThinWaker>,
}
unsafe impl Send for WakerInner {}
unsafe impl Sync for WakerInner {}
impl WakerInner {
#[inline(always)]
fn get_waker(&self) -> &ThinWaker {
unsafe { &*self.waker.get() }
}
#[inline(always)]
fn get_waker_mut(&self) -> &mut ThinWaker {
unsafe { &mut *self.waker.get() }
}
#[inline(always)]
pub fn reset(&self) {
self.reset_init();
}
#[inline(always)]
pub fn get_seq(&self) -> u32 {
self.seq.load(Ordering::Relaxed)
}
#[inline(always)]
pub fn set_seq(&self, seq: u32) {
self.seq.store(seq, Ordering::Relaxed);
}
#[inline(always)]
fn update_thread_handle(&self) {
let _waker = self.get_waker_mut();
*_waker = ThinWaker::Blocking(thread::current());
}
#[inline(always)]
pub fn commit_waiting(&self) -> u8 {
if let Err(s) = self.try_change_state(WakerState::Init, WakerState::Waiting) {
s
} else {
WakerState::Waiting as u8
}
}
#[inline(always)]
pub fn try_change_state(&self, cur: WakerState, new_state: WakerState) -> Result<(), u8> {
self.state.compare_exchange(
cur as u8,
new_state as u8,
Ordering::SeqCst,
Ordering::Acquire,
)?;
Ok(())
}
#[inline(always)]
pub fn reset_init(&self) {
self.state.store(WakerState::Init as u8, Ordering::Relaxed);
}
#[inline(always)]
pub fn abandon(&self) -> Result<(), u8> {
match self.change_state_smaller_eq(WakerState::Waiting, WakerState::Closed) {
Ok(_) => Ok(()),
Err(state) => Err(state),
}
}
#[inline(always)]
pub fn close_wake(&self) -> bool {
if self.change_state_smaller_eq(WakerState::Waiting, WakerState::Closed).is_ok() {
self.get_waker().wake_by_ref();
return true;
}
false
}
#[inline(always)]
pub fn change_state_smaller_eq(
&self, condition: WakerState, target: WakerState,
) -> Result<u8, u8> {
debug_assert!((condition as u8) < (target as u8));
let mut state = condition as u8;
loop {
match self.state.compare_exchange_weak(
state,
target as u8,
Ordering::SeqCst,
Ordering::Acquire,
) {
Ok(_) => {
return Ok(state);
}
Err(s) => {
if s > condition as u8 {
return Err(s);
}
state = s;
}
}
}
}
#[inline(always)]
pub fn _get_state(&self, order: Ordering) -> u8 {
self.state.load(order)
}
#[inline(always)]
pub fn get_state(&self) -> u8 {
self.state.load(Ordering::SeqCst)
}
#[inline(always)]
pub fn get_state_relaxed(&self) -> u8 {
self.state.load(Ordering::Relaxed)
}
#[inline(always)]
pub fn wake(&self) -> WakeResult {
let mut state = self.get_state_relaxed();
loop {
if state >= WakerState::Woken as u8 {
return WakeResult::Skip;
} else if state == WakerState::Waiting as u8 {
self.state.store(WakerState::Woken as u8, Ordering::SeqCst);
self.get_waker().wake_by_ref();
return WakeResult::Woken;
} else {
match self.state.compare_exchange_weak(
WakerState::Init as u8,
WakerState::Woken as u8,
Ordering::SeqCst,
Ordering::Acquire,
) {
Ok(_) => {
self.get_waker().wake_by_ref();
return WakeResult::Next;
}
Err(s) => {
state = s;
}
}
}
}
}
#[inline(always)]
pub fn will_wake(&self, ctx: &mut Context) -> bool {
self.get_waker().will_wake(ctx)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_waker_size() {
use std::mem::size_of;
println!("wakertype {}", size_of::<ThinWaker>());
println!("waker inner {}", size_of::<WakerInner>());
}
}