#![allow(dead_code)]
use core::fmt;
use core::cell::UnsafeCell;
use core::sync::atomic::AtomicUsize;
use core::sync::atomic::Ordering::{Acquire, Release};
use task::Waker;
pub struct AtomicWaker {
state: AtomicUsize,
task: UnsafeCell<Option<Waker>>,
}
const WAITING: usize = 2;
const LOCKED_WRITE: usize = 0;
const LOCKED_WRITE_NOTIFIED: usize = 1;
#[allow(dead_code)]
const LOCKED_READ: usize = 3;
impl AtomicWaker {
pub fn new() -> AtomicWaker {
trait AssertSync: Sync {}
impl AssertSync for Waker {}
AtomicWaker {
state: AtomicUsize::new(WAITING),
task: UnsafeCell::new(None),
}
}
pub fn register(&self, task: Waker) {
match self.state.compare_and_swap(WAITING, LOCKED_WRITE, Acquire) {
WAITING => {
unsafe {
*self.task.get() = Some(task);
if LOCKED_WRITE_NOTIFIED == self.state.swap(WAITING, Release) {
(*self.task.get()).as_ref().unwrap().wake();
}
}
}
LOCKED_WRITE | LOCKED_WRITE_NOTIFIED => {
}
state => {
debug_assert!(state != LOCKED_WRITE, "unexpected state LOCKED_WRITE");
debug_assert!(state != LOCKED_WRITE_NOTIFIED, "unexpected state LOCKED_WRITE_NOTIFIED");
task.wake();
}
}
}
pub fn wake(&self) {
let mut curr = WAITING;
loop {
if curr == LOCKED_WRITE {
let actual = self.state.compare_and_swap(LOCKED_WRITE, LOCKED_WRITE_NOTIFIED, Release);
if curr == actual {
return;
}
curr = actual;
} else if curr == LOCKED_WRITE_NOTIFIED {
return;
} else {
let actual = self.state.compare_and_swap(curr, curr + 1, Acquire);
if actual == curr {
unsafe {
if let Some(ref task) = *self.task.get() {
task.wake();
}
}
self.state.fetch_sub(1, Release);
return;
}
curr = actual;
}
}
}
}
impl Default for AtomicWaker {
fn default() -> Self {
AtomicWaker::new()
}
}
impl fmt::Debug for AtomicWaker {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "AtomicWaker")
}
}
unsafe impl Send for AtomicWaker {}
unsafe impl Sync for AtomicWaker {}