use core::{future::poll_fn, task::Poll};
use ax_errno::{AxError, AxResult};
use axpoll::{IoEvents, Pollable};
pub async fn poll_io<P: Pollable, F: FnMut() -> AxResult<T>, T>(
pollable: &P,
events: IoEvents,
non_blocking: bool,
mut f: F,
) -> AxResult<T> {
super::interruptible(poll_fn(move |cx| match f() {
Ok(value) => Poll::Ready(Ok(value)),
Err(AxError::WouldBlock) => {
if non_blocking {
return Poll::Ready(Err(AxError::WouldBlock));
}
pollable.register(cx, events);
match f() {
Ok(value) => Poll::Ready(Ok(value)),
Err(AxError::WouldBlock) => Poll::Pending,
Err(e) => Poll::Ready(Err(e)),
}
}
Err(e) => Poll::Ready(Err(e)),
}))
.await?
}
#[cfg(feature = "irq")]
pub fn register_irq_waker(irq: usize, waker: &core::task::Waker) {
use alloc::collections::BTreeMap;
use ax_kspin::SpinNoIrq;
use axpoll::PollSet;
static POLL_IRQ: SpinNoIrq<BTreeMap<usize, PollSet>> = SpinNoIrq::new(BTreeMap::new());
fn irq_hook(irq: usize) {
if let Some(s) = POLL_IRQ.lock().get(&irq) {
s.wake();
}
}
ax_hal::irq::register_irq_hook(irq_hook);
POLL_IRQ.lock().entry(irq).or_default().register(waker);
ax_hal::irq::set_enable(irq, true);
}