use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::task::Context;
use std::task::Poll;
use std::task::Wake;
use std::task::Waker;
use qubit_clock::TimerFuture;
struct ThreadWaker {
thread: std::thread::Thread,
notified: AtomicBool,
}
impl ThreadWaker {
#[must_use]
#[inline]
fn new(thread: std::thread::Thread) -> Self {
Self {
thread,
notified: AtomicBool::new(false),
}
}
#[inline(always)]
fn prepare_to_poll(&self) {
self.notified.store(false, Ordering::Release);
}
fn park_until_notified(&self) {
while !self.notified.swap(false, Ordering::AcqRel) {
std::thread::park();
}
}
}
impl Wake for ThreadWaker {
#[inline(always)]
fn wake(self: Arc<Self>) {
self.wake_by_ref();
}
#[inline(always)]
fn wake_by_ref(self: &Arc<Self>) {
self.notified.store(true, Ordering::Release);
self.thread.unpark();
}
}
pub(crate) fn block_on_timer_future(mut future: TimerFuture) {
let thread_waker = Arc::new(ThreadWaker::new(std::thread::current()));
let waker = Waker::from(Arc::clone(&thread_waker));
let mut context = Context::from_waker(&waker);
loop {
thread_waker.prepare_to_poll();
if let Poll::Ready(result) = future.as_mut().poll(&mut context) {
return result.expect("timer should complete");
}
thread_waker.park_until_notified();
}
}