aboutsummaryrefslogtreecommitdiff
path: root/embassy-time-queue-driver
diff options
context:
space:
mode:
authorDániel Buga <[email protected]>2024-12-08 23:21:53 +0100
committerDániel Buga <[email protected]>2024-12-12 15:38:52 +0100
commitd45ea43892198484b5f6dcea4c351dc11d226cc4 (patch)
tree54dd8011d3dea264095c28c8be003f66f8600ce6 /embassy-time-queue-driver
parentdc18ee29a0f93ce34892731ee0580a3e9e3f2298 (diff)
Move integrated timer queue into time-queue-driver
Diffstat (limited to 'embassy-time-queue-driver')
-rw-r--r--embassy-time-queue-driver/src/lib.rs11
-rw-r--r--embassy-time-queue-driver/src/queue_integrated.rs78
2 files changed, 85 insertions, 4 deletions
diff --git a/embassy-time-queue-driver/src/lib.rs b/embassy-time-queue-driver/src/lib.rs
index c5e989854..0c78921ed 100644
--- a/embassy-time-queue-driver/src/lib.rs
+++ b/embassy-time-queue-driver/src/lib.rs
@@ -22,9 +22,9 @@
22//! ); 22//! );
23//! ``` 23//! ```
24//! 24//!
25//! You can also use the `queue_generic` or the `embassy_executor::raw::timer_queue` modules to 25//! You can also use the `queue_generic` or the `queue_integrated` modules to implement your own
26//! implement your own timer queue. These modules contain queue implementations which you can wrap 26//! timer queue. These modules contain queue implementations which you can wrap and tailor to
27//! and tailor to your needs. 27//! your needs.
28//! 28//!
29//! If you are providing an embassy-executor implementation besides a timer queue, you can choose to 29//! If you are providing an embassy-executor implementation besides a timer queue, you can choose to
30//! expose the `integrated-timers` feature in your implementation. This feature stores timer items 30//! expose the `integrated-timers` feature in your implementation. This feature stores timer items
@@ -49,7 +49,10 @@
49//! embassy_time_queue_driver::timer_queue_impl!(static QUEUE: MyTimerQueue = MyTimerQueue{}); 49//! embassy_time_queue_driver::timer_queue_impl!(static QUEUE: MyTimerQueue = MyTimerQueue{});
50//! ``` 50//! ```
51 51
52#[cfg(not(feature = "integrated-timers"))]
52pub mod queue_generic; 53pub mod queue_generic;
54#[cfg(feature = "integrated-timers")]
55pub mod queue_integrated;
53 56
54use core::cell::RefCell; 57use core::cell::RefCell;
55use core::task::Waker; 58use core::task::Waker;
@@ -89,7 +92,7 @@ macro_rules! timer_queue_impl {
89} 92}
90 93
91#[cfg(feature = "integrated-timers")] 94#[cfg(feature = "integrated-timers")]
92type InnerQueue = embassy_executor::raw::timer_queue::TimerQueue; 95type InnerQueue = queue_integrated::TimerQueue;
93 96
94#[cfg(not(feature = "integrated-timers"))] 97#[cfg(not(feature = "integrated-timers"))]
95type InnerQueue = queue_generic::Queue; 98type InnerQueue = queue_generic::Queue;
diff --git a/embassy-time-queue-driver/src/queue_integrated.rs b/embassy-time-queue-driver/src/queue_integrated.rs
new file mode 100644
index 000000000..cb0f79356
--- /dev/null
+++ b/embassy-time-queue-driver/src/queue_integrated.rs
@@ -0,0 +1,78 @@
1//! Timer queue operations.
2use core::cell::Cell;
3use core::cmp::min;
4
5use embassy_executor::raw::TaskRef;
6
7/// A timer queue, with items integrated into tasks.
8pub struct TimerQueue {
9 head: Cell<Option<TaskRef>>,
10}
11
12impl TimerQueue {
13 /// Creates a new timer queue.
14 pub const fn new() -> Self {
15 Self { head: Cell::new(None) }
16 }
17
18 /// Schedules a task to run at a specific time.
19 ///
20 /// If this function returns `true`, the called should find the next expiration time and set
21 /// a new alarm for that time.
22 pub fn schedule_wake(&mut self, at: u64, p: TaskRef) -> bool {
23 let item = p.timer_queue_item();
24 if item.next.get().is_none() {
25 // If not in the queue, add it and update.
26 let prev = self.head.replace(Some(p));
27 item.next.set(prev);
28 } else if at <= item.expires_at.get() {
29 // If expiration is sooner than previously set, update.
30 } else {
31 // Task does not need to be updated.
32 return false;
33 }
34
35 item.expires_at.set(at);
36 true
37 }
38
39 /// Dequeues expired timers and returns the next alarm time.
40 ///
41 /// The provided callback will be called for each expired task. Tasks that never expire
42 /// will be removed, but the callback will not be called.
43 pub fn next_expiration(&mut self, now: u64) -> u64 {
44 let mut next_expiration = u64::MAX;
45
46 self.retain(|p| {
47 let item = p.timer_queue_item();
48 let expires = item.expires_at.get();
49
50 if expires <= now {
51 // Timer expired, process task.
52 embassy_executor::raw::wake_task(p);
53 false
54 } else {
55 // Timer didn't yet expire, or never expires.
56 next_expiration = min(next_expiration, expires);
57 expires != u64::MAX
58 }
59 });
60
61 next_expiration
62 }
63
64 fn retain(&self, mut f: impl FnMut(TaskRef) -> bool) {
65 let mut prev = &self.head;
66 while let Some(p) = prev.get() {
67 let item = p.timer_queue_item();
68 if f(p) {
69 // Skip to next
70 prev = &item.next;
71 } else {
72 // Remove it
73 prev.set(item.next.get());
74 item.next.set(None);
75 }
76 }
77 }
78}