1use core::{future::poll_fn, task::Poll};
2
3use axpoll::{IoEvents, Pollable};
4
5use super::{Interrupted, PollIoError, TaskResult};
6use crate::current;
7
8pub async fn poll_io<P, F, T, E>(
21 pollable: &P,
22 events: IoEvents,
23 non_blocking: bool,
24 mut f: F,
25) -> Result<T, E>
26where
27 P: Pollable,
28 F: FnMut() -> Result<T, E>,
29 E: PollIoError,
30{
31 let curr = current();
32 poll_fn(move |cx| {
33 match f() {
34 Ok(value) => return Poll::Ready(Ok(value)),
35 Err(error) if error.is_would_block() => {}
36 Err(e) => return Poll::Ready(Err(e)),
37 }
38
39 pollable.register(cx, events);
44
45 match f() {
46 Ok(value) => Poll::Ready(Ok(value)),
47 Err(error) if error.is_would_block() && non_blocking => Poll::Ready(Err(error)),
48 Err(error) if error.is_would_block() => {
49 if curr.poll_interrupt(cx).is_ready() {
50 Poll::Ready(Err(E::interrupted(Interrupted)))
51 } else {
52 Poll::Pending
53 }
54 }
55 Err(e) => Poll::Ready(Err(e)),
56 }
57 })
58 .await
59}
60
61pub fn register_irq_waker(irq: ax_hal::irq::IrqId, waker: &core::task::Waker) -> TaskResult {
77 use alloc::{collections::BTreeMap, sync::Arc};
78 use core::sync::atomic::{AtomicBool, Ordering};
79
80 use axpoll::PollSet;
81
82 use crate::{IrqNotify, sync::SpinLock};
83
84 static IRQ_NOTIFY: IrqNotify = IrqNotify::new();
85 static DRAIN_SPAWNED: AtomicBool = AtomicBool::new(false);
86 static IRQ_STATE: SpinLock<BTreeMap<ax_hal::irq::IrqId, IrqPollState>> =
87 SpinLock::new(BTreeMap::new());
88
89 struct IrqPollState {
90 pending: bool,
91 installed: bool,
92 poll: Arc<PollSet>,
93 }
94
95 fn irq_waker_handler(ctx: ax_hal::irq::IrqContext) -> ax_hal::irq::IrqReturn {
96 if let Some(state) = IRQ_STATE.lock_irqsave().get_mut(&ctx.irq) {
100 state.pending = true;
101 IRQ_NOTIFY.notify_irq();
102 ax_hal::irq::IrqReturn::Handled
103 } else {
104 ax_hal::irq::IrqReturn::Unhandled
105 }
106 }
107
108 fn ensure_drain_spawned() {
109 if DRAIN_SPAWNED
110 .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
111 .is_err()
112 {
113 return;
114 }
115 crate::spawn_raw(
116 || {
117 loop {
118 IRQ_NOTIFY.wait();
119
120 let mut to_wake: alloc::vec::Vec<Arc<PollSet>> = alloc::vec::Vec::new();
125 {
126 let mut map = IRQ_STATE.lock_irqsave();
127 for state in map.values_mut() {
128 if state.pending {
129 state.pending = false;
130 to_wake.push(state.poll.clone());
131 }
132 }
133 }
134 for set in to_wake {
135 unsafe { set.wake(axpoll::IoEvents::all()) };
136 }
137 }
138 },
139 alloc::string::String::from("irq_waker_drain"),
140 0x4000,
141 );
142 }
143
144 ensure_drain_spawned();
145
146 let (poll, should_install) = {
147 let mut map = IRQ_STATE.lock_irqsave();
148 let state = map.entry(irq).or_insert_with(|| IrqPollState {
149 pending: false,
150 installed: false,
151 poll: Arc::new(PollSet::new()),
152 });
153 if state.installed {
154 (state.poll.clone(), false)
155 } else {
156 state.installed = true;
157 (state.poll.clone(), true)
158 }
159 };
160 unsafe { poll.register(waker, axpoll::IoEvents::all()) };
161
162 if should_install {
163 ax_hal::irq::request_shared_irq(irq, irq_waker_handler)?;
164 }
165
166 ax_hal::irq::set_enable(irq, true)?;
167 Ok(())
168}
169
170pub fn register_legacy_irq_waker(irq: usize, waker: &core::task::Waker) -> TaskResult {
172 let irq = ax_hal::irq::try_legacy_irq(irq)?;
173 register_irq_waker(irq, waker)
174}