extern crate alloc;
use crate::util::{calc_freq_blocking, tick};
use alloc::boxed::Box;
use core::pin::Pin;
use core::task::{Context, Poll, Waker};
pub use uefi_async_macros::add;
pub struct TaskNode<'curr, 'next> {
future: Pin<Box<dyn Future<Output = ()> + 'curr>>,
interval: u64,
next_run_time: u64,
next: Option<&'next mut TaskNode<'curr, 'next>>,
}
impl<'curr, 'next> TaskNode<'curr, 'next> {
#[inline]
pub fn new(future: Pin<Box<dyn Future<Output = ()> + 'curr>>, freq: u64) -> Self {
Self { future, interval: freq, next_run_time: 0, next: None }
}
}
pub struct Executor<'curr, 'next> {
head: Option<&'next mut TaskNode<'curr, 'next>>,
freq: u64,
}
impl<'curr, 'next> Executor<'curr, 'next> {
#[inline]
pub fn new() -> Self {
Self{ head: None, freq: calc_freq_blocking() }
}
#[inline]
pub fn add(&mut self, node: &'next mut TaskNode<'curr, 'next>) -> &mut Self {
node.interval = self.freq.checked_div(node.interval).unwrap_or(0);
node.next = self.head.take();
self.head = Some(node);
self
}
#[inline]
pub fn run_forever(&mut self) {
let mut cx = Self::init_step();
loop { self.run_step(tick(), &mut cx) }
}
#[inline(always)]
pub fn init_step() -> Context<'curr> {
Context::from_waker(&Waker::noop())
}
#[inline]
pub fn run_step(&mut self, time: u64, cx: &mut Context) {
let mut cursor = &mut self.head;
while let Some(node) = cursor {
if time >= node.next_run_time {
match node.future.as_mut().poll(cx) {
Poll::Ready(_) => *cursor = node.next.take(),
Poll::Pending => node.next_run_time = time + node.interval,
}
}
cursor = match { cursor } {
Some(node) => &mut node.next,
None => break,
};
}
}
}