use std::cell::UnsafeCell;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;
pub(crate) struct UnparkMutex<D> {
status: AtomicUsize,
inner: UnsafeCell<Option<D>>,
}
unsafe impl<D: Send> Send for UnparkMutex<D> {}
unsafe impl<D: Send> Sync for UnparkMutex<D> {}
const WAITING: usize = 0;
const POLLING: usize = 1;
const REPOLL: usize = 2;
const COMPLETE: usize = 3;
impl<D> UnparkMutex<D> {
pub(crate) fn new() -> UnparkMutex<D> {
UnparkMutex {
status: AtomicUsize::new(WAITING),
inner: UnsafeCell::new(None),
}
}
pub(crate) fn notify(&self) -> Result<D, ()> {
let mut status = self.status.load(SeqCst);
loop {
match status {
WAITING => {
match self.status.compare_exchange(WAITING, POLLING,
SeqCst, SeqCst) {
Ok(_) => {
let data = unsafe {
(*self.inner.get()).take().unwrap()
};
return Ok(data);
}
Err(cur) => status = cur,
}
}
POLLING => {
match self.status.compare_exchange(POLLING, REPOLL,
SeqCst, SeqCst) {
Ok(_) => return Err(()),
Err(cur) => status = cur,
}
}
_ => return Err(()),
}
}
}
pub(crate) unsafe fn start_poll(&self) {
self.status.store(POLLING, SeqCst);
}
pub(crate) unsafe fn wait(&self, data: D) -> Result<(), D> {
*self.inner.get() = Some(data);
match self.status.compare_exchange(POLLING, WAITING, SeqCst, SeqCst) {
Ok(_) => Ok(()),
Err(status) => {
assert_eq!(status, REPOLL);
self.status.store(POLLING, SeqCst);
Err((*self.inner.get()).take().unwrap())
}
}
}
pub(crate) unsafe fn complete(&self) {
self.status.store(COMPLETE, SeqCst);
}
}