use alloc::{sync::Arc, task::Wake};
use core::{
fmt,
future::poll_fn,
pin::pin,
task::{Context, Poll, Waker},
};
use ax_errno::AxError;
use ax_kernel_guard::NoPreemptIrqSave;
use ax_kspin::SpinNoIrq;
use crate::{AxTaskRef, WeakAxTaskRef, current, current_run_queue, select_run_queue};
mod poll;
pub use poll::*;
mod time;
pub use time::*;
struct AxWaker {
task: WeakAxTaskRef,
woke: SpinNoIrq<bool>,
}
impl AxWaker {
fn new(task: &AxTaskRef) -> Arc<Self> {
Arc::new(AxWaker {
task: Arc::downgrade(task),
woke: SpinNoIrq::new(false),
})
}
}
impl Wake for AxWaker {
fn wake(self: Arc<Self>) {
self.wake_by_ref();
}
fn wake_by_ref(self: &Arc<Self>) {
if let Some(task) = self.task.upgrade() {
let mut rq = select_run_queue::<NoPreemptIrqSave>(&task);
*self.woke.lock() = true;
rq.unblock_task(task, false);
}
}
}
pub fn block_on<F: IntoFuture>(f: F) -> F::Output {
crate::api::might_sleep();
let mut fut = pin!(f.into_future());
let curr = current();
let task = curr.clone();
let axwaker = AxWaker::new(&task);
let waker = Waker::from(axwaker.clone());
let mut cx = Context::from_waker(&waker);
loop {
match fut.as_mut().poll(&mut cx) {
Poll::Pending => {
let mut rq = current_run_queue::<NoPreemptIrqSave>();
let mut woke = axwaker.woke.lock();
if !*woke {
rq.future_blocked_resched(woke);
} else {
*woke = false;
drop(woke);
drop(rq);
crate::yield_now();
}
}
Poll::Ready(output) => break output,
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct Interrupted;
impl fmt::Display for Interrupted {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "interrupted")
}
}
impl core::error::Error for Interrupted {}
impl From<Interrupted> for AxError {
fn from(_: Interrupted) -> Self {
AxError::Interrupted
}
}
pub async fn interruptible<F: IntoFuture>(f: F) -> Result<F::Output, Interrupted> {
let mut f = pin!(f.into_future());
let curr = current();
poll_fn(|cx| {
if curr.poll_interrupt(cx).is_ready() {
return Poll::Ready(Err(Interrupted));
}
f.as_mut().poll(cx).map(Ok)
})
.await
}