1use alloc::vec::Vec;
15use core::cell::RefCell;
16use core::future::Future;
17use core::pin::Pin;
18use core::task::{Context, Poll, Waker};
19
20use crate::core::error::Result;
21use crate::core::line::{CompletionLine, MemoryDescriptor, reached};
22use crate::core::time::{Clock, DurNs, MonoNs, Timer};
23use crate::error;
24
25pub trait Idle {
28 fn sleep_until(&mut self, at: MonoNs);
30
31 fn park_line<R: Fn(&CompletionLine) -> bool>(
34 &mut self,
35 line: &CompletionLine,
36 ready: R,
37 bound: DurNs,
38 ) -> bool;
39}
40
41struct Source<'l> {
42 id: u64,
43 desc: MemoryDescriptor<'l>,
44 until: Option<MonoNs>,
45 waker: Waker,
46}
47
48struct Alarm {
49 id: u64,
50 at: MonoNs,
51 waker: Waker,
52}
53
54#[derive(Default)]
55struct Table<'l> {
56 next_id: u64,
57 sources: Vec<Source<'l>>,
58 alarms: Vec<Alarm>,
59}
60
61#[derive(Clone, Copy, Debug, PartialEq, Eq)]
63pub enum Turn {
64 Woke,
66 Slept,
68 Parked,
70}
71
72pub struct Reactor<'l, C: Clock> {
74 clock: C,
75 table: RefCell<Table<'l>>,
76}
77
78impl<'l, C: Clock> Reactor<'l, C> {
79 #[must_use]
81 pub fn new(clock: C) -> Self {
82 Self {
83 clock,
84 table: RefCell::new(Table::default()),
85 }
86 }
87
88 #[must_use]
90 pub fn clock(&self) -> &C {
91 &self.clock
92 }
93
94 #[must_use]
97 pub fn ready(&self, desc: MemoryDescriptor<'l>, until: Option<MonoNs>) -> Ready<'_, 'l, C> {
98 Ready {
99 reactor: self,
100 desc,
101 until,
102 id: None,
103 }
104 }
105
106 #[must_use]
108 pub fn pending(&self) -> (usize, usize) {
109 let t = self.table.borrow();
110 (t.sources.len(), t.alarms.len())
111 }
112
113 pub fn turn<I: Idle>(&self, idle: &mut I, park_bound: DurNs, tasks_left: usize) -> Result<Turn> {
119 if self.fire() {
120 return Ok(Turn::Woke);
121 }
122 let now = self.clock.monotonic_ns();
123 let (deadline, line) = {
124 let t = self.table.borrow();
125 let deadline = t
126 .alarms
127 .iter()
128 .map(|a| a.at)
129 .chain(t.sources.iter().filter_map(|s| s.until))
130 .min();
131 (deadline, t.sources.first().map(|s| s.desc.line()))
132 };
133 match (line, deadline) {
134 (None, None) => Err(error!(Stalled, tasks_left)),
135 (None, Some(at)) => {
136 idle.sleep_until(at);
137 Ok(Turn::Slept)
138 }
139 (Some(line), deadline) => {
140 let bound = deadline.map_or(park_bound, |d| park_bound.min(d.since(now)));
141 let watched: Vec<_> = {
142 let t = self.table.borrow();
143 t.sources
144 .iter()
145 .filter(|s| core::ptr::eq(s.desc.line(), line))
146 .map(|s| (s.desc.slot(), s.desc.target()))
147 .collect()
148 };
149 idle.park_line(
150 line,
151 |l| watched.iter().any(|&(slot, target)| reached(l, slot, target)),
152 bound,
153 );
154 Ok(Turn::Parked)
155 }
156 }
157 }
158
159 pub fn fire(&self) -> bool {
163 let now = self.clock.monotonic_ns();
164 let due = {
165 let mut t = self.table.borrow_mut();
166 let mut due = Vec::new();
167 t.sources.retain_mut(|s| {
168 let fire = s.desc.is_complete() || s.until.is_some_and(|u| now >= u);
169 if fire {
170 due.push(s.waker.clone());
171 }
172 !fire
173 });
174 t.alarms.retain(|a| {
175 let fire = now >= a.at;
176 if fire {
177 due.push(a.waker.clone());
178 }
179 !fire
180 });
181 due
182 };
183 let any = !due.is_empty();
184 for w in due {
185 w.wake();
186 }
187 any
188 }
189
190 fn register_source(&self, id: &mut Option<u64>, desc: MemoryDescriptor<'l>, until: Option<MonoNs>, waker: &Waker) {
191 let mut t = self.table.borrow_mut();
192 if let Some(i) = *id
193 && let Some(s) = t.sources.iter_mut().find(|s| s.id == i)
194 {
195 s.waker.clone_from(waker);
196 return;
197 }
198 t.next_id += 1;
199 let i = t.next_id;
200 *id = Some(i);
201 t.sources.push(Source {
202 id: i,
203 desc,
204 until,
205 waker: waker.clone(),
206 });
207 }
208
209 fn register_alarm(&self, id: &mut Option<u64>, at: MonoNs, waker: &Waker) {
210 let mut t = self.table.borrow_mut();
211 if let Some(i) = *id
212 && let Some(a) = t.alarms.iter_mut().find(|a| a.id == i)
213 {
214 a.waker.clone_from(waker);
215 return;
216 }
217 t.next_id += 1;
218 let i = t.next_id;
219 *id = Some(i);
220 t.alarms.push(Alarm {
221 id: i,
222 at,
223 waker: waker.clone(),
224 });
225 }
226
227 fn forget(&self, id: Option<u64>) {
228 if let Some(i) = id {
229 let mut t = self.table.borrow_mut();
230 t.sources.retain(|s| s.id != i);
231 t.alarms.retain(|a| a.id != i);
232 }
233 }
234}
235
236pub struct Ready<'r, 'l, C: Clock> {
238 reactor: &'r Reactor<'l, C>,
239 desc: MemoryDescriptor<'l>,
240 until: Option<MonoNs>,
241 id: Option<u64>,
242}
243
244impl<C: Clock> Future for Ready<'_, '_, C> {
245 type Output = bool;
246
247 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<bool> {
248 let this = self.get_mut();
249 if this.desc.is_complete() {
250 this.reactor.forget(this.id.take());
251 return Poll::Ready(true);
252 }
253 if this
254 .until
255 .is_some_and(|u| this.reactor.clock.monotonic_ns() >= u)
256 {
257 this.reactor.forget(this.id.take());
258 return Poll::Ready(false);
259 }
260 this.reactor
261 .register_source(&mut this.id, this.desc, this.until, cx.waker());
262 Poll::Pending
263 }
264}
265
266impl<C: Clock> Drop for Ready<'_, '_, C> {
267 fn drop(&mut self) {
268 self.reactor.forget(self.id.take());
269 }
270}
271
272pub struct Alarmed<'r, 'l, C: Clock> {
274 reactor: &'r Reactor<'l, C>,
275 at: MonoNs,
276 id: Option<u64>,
277}
278
279impl<C: Clock> Future for Alarmed<'_, '_, C> {
280 type Output = ();
281
282 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
283 let this = self.get_mut();
284 if this.reactor.clock.monotonic_ns() >= this.at {
285 this.reactor.forget(this.id.take());
286 return Poll::Ready(());
287 }
288 this.reactor.register_alarm(&mut this.id, this.at, cx.waker());
289 Poll::Pending
290 }
291}
292
293impl<C: Clock> Drop for Alarmed<'_, '_, C> {
294 fn drop(&mut self) {
295 self.reactor.forget(self.id.take());
296 }
297}
298
299impl<'l, C: Clock> Reactor<'l, C> {
300 #[must_use]
302 pub fn alarm(&self, at: MonoNs) -> Alarmed<'_, 'l, C> {
303 Alarmed {
304 reactor: self,
305 at,
306 id: None,
307 }
308 }
309}
310
311impl<C: Clock> Timer for Reactor<'_, C> {
312 async fn sleep_until(&self, at: MonoNs) {
313 self.alarm(at).await;
314 }
315}
316
317impl<C: Clock> Clock for Reactor<'_, C> {
318 fn monotonic_ns(&self) -> MonoNs {
319 self.clock.monotonic_ns()
320 }
321}
322
323#[cfg(test)]
324#[path = "reactor_tests.rs"]
325pub(crate) mod tests;