2024-12-22 21:00:23 +01:00

147 lines
3.8 KiB
Rust

//! Generic timer queue implementations.
//!
//! Time queue drivers may use this to simplify their implementation.
use core::cmp::{min, Ordering};
use core::task::Waker;
use heapless::Vec;
#[derive(Debug)]
struct Timer {
at: u64,
waker: Waker,
}
impl PartialEq for Timer {
fn eq(&self, other: &Self) -> bool {
self.at == other.at
}
}
impl Eq for Timer {}
impl PartialOrd for Timer {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.at.partial_cmp(&other.at)
}
}
impl Ord for Timer {
fn cmp(&self, other: &Self) -> Ordering {
self.at.cmp(&other.at)
}
}
/// A timer queue with a pre-determined capacity.
pub struct ConstGenericQueue<const QUEUE_SIZE: usize> {
queue: Vec<Timer, QUEUE_SIZE>,
}
impl<const QUEUE_SIZE: usize> ConstGenericQueue<QUEUE_SIZE> {
/// Creates a new timer queue.
pub const fn new() -> Self {
Self { queue: Vec::new() }
}
/// Schedules a task to run at a specific time, and returns whether any changes were made.
///
/// If this function returns `true`, the called should find the next expiration time and set
/// a new alarm for that time.
pub fn schedule_wake(&mut self, at: u64, waker: &Waker) -> bool {
self.queue
.iter_mut()
.find(|timer| timer.waker.will_wake(waker))
.map(|timer| {
if timer.at > at {
timer.at = at;
true
} else {
false
}
})
.unwrap_or_else(|| {
let mut timer = Timer {
waker: waker.clone(),
at,
};
loop {
match self.queue.push(timer) {
Ok(()) => break,
Err(e) => timer = e,
}
self.queue.pop().unwrap().waker.wake();
}
true
})
}
/// Dequeues expired timers and returns the next alarm time.
pub fn next_expiration(&mut self, now: u64) -> u64 {
let mut next_alarm = u64::MAX;
let mut i = 0;
while i < self.queue.len() {
let timer = &self.queue[i];
if timer.at <= now {
let timer = self.queue.swap_remove(i);
timer.waker.wake();
} else {
next_alarm = min(next_alarm, timer.at);
i += 1;
}
}
next_alarm
}
}
#[cfg(feature = "generic-queue-8")]
const QUEUE_SIZE: usize = 8;
#[cfg(feature = "generic-queue-16")]
const QUEUE_SIZE: usize = 16;
#[cfg(feature = "generic-queue-32")]
const QUEUE_SIZE: usize = 32;
#[cfg(feature = "generic-queue-64")]
const QUEUE_SIZE: usize = 64;
#[cfg(feature = "generic-queue-128")]
const QUEUE_SIZE: usize = 128;
#[cfg(not(any(
feature = "generic-queue-8",
feature = "generic-queue-16",
feature = "generic-queue-32",
feature = "generic-queue-64",
feature = "generic-queue-128"
)))]
const QUEUE_SIZE: usize = 64;
/// A timer queue with a pre-determined capacity.
pub struct Queue {
queue: ConstGenericQueue<QUEUE_SIZE>,
}
impl Queue {
/// Creates a new timer queue.
pub const fn new() -> Self {
Self {
queue: ConstGenericQueue::new(),
}
}
/// Schedules a task to run at a specific time, and returns whether any changes were made.
///
/// If this function returns `true`, the called should find the next expiration time and set
/// a new alarm for that time.
pub fn schedule_wake(&mut self, at: u64, waker: &Waker) -> bool {
self.queue.schedule_wake(at, waker)
}
/// Dequeues expired timers and returns the next alarm time.
pub fn next_expiration(&mut self, now: u64) -> u64 {
self.queue.next_expiration(now)
}
}