aboutsummaryrefslogtreecommitdiff
path: root/embassy-time-queue-driver
diff options
context:
space:
mode:
authorDániel Buga <[email protected]>2024-12-20 12:45:24 +0100
committerDániel Buga <[email protected]>2024-12-22 21:00:23 +0100
commitab8ca3f126447edb3a9eb06aa6fd6cd394219c17 (patch)
tree129bff555ec2fee297a932243de03151ec38712c /embassy-time-queue-driver
parent1c485f18a2ee6147bf4cfd66789dc8e0c6e1466c (diff)
Rename ETQD, bump date
Diffstat (limited to 'embassy-time-queue-driver')
-rw-r--r--embassy-time-queue-driver/CHANGELOG.md15
-rw-r--r--embassy-time-queue-driver/Cargo.toml58
-rw-r--r--embassy-time-queue-driver/README.md8
-rw-r--r--embassy-time-queue-driver/build.rs1
-rw-r--r--embassy-time-queue-driver/src/lib.rs20
-rw-r--r--embassy-time-queue-driver/src/queue_generic.rs146
-rw-r--r--embassy-time-queue-driver/src/queue_integrated.rs89
7 files changed, 0 insertions, 337 deletions
diff --git a/embassy-time-queue-driver/CHANGELOG.md b/embassy-time-queue-driver/CHANGELOG.md
deleted file mode 100644
index 46d00c87d..000000000
--- a/embassy-time-queue-driver/CHANGELOG.md
+++ /dev/null
@@ -1,15 +0,0 @@
1# Changelog for embassy-time-queue-driver
2
3All notable changes to this project will be documented in this file.
4
5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
8## 0.2.0 - 2024-12-18
9
10- Added `generic-queue-N` features.
11- Added `embassy_time_queue_driver::Queue` struct which uses integrated or a generic storage (configured using `generic-queue-N`).
12
13## 0.1.0 - 2024-01-11
14
15Initial release
diff --git a/embassy-time-queue-driver/Cargo.toml b/embassy-time-queue-driver/Cargo.toml
deleted file mode 100644
index 990393cc0..000000000
--- a/embassy-time-queue-driver/Cargo.toml
+++ /dev/null
@@ -1,58 +0,0 @@
1[package]
2name = "embassy-time-queue-driver"
3version = "0.2.0"
4edition = "2021"
5description = "Timer queue driver trait for embassy-time"
6repository = "https://github.com/embassy-rs/embassy"
7documentation = "https://docs.embassy.dev/embassy-time-queue-driver"
8readme = "README.md"
9license = "MIT OR Apache-2.0"
10categories = [
11 "embedded",
12 "no-std",
13 "concurrency",
14 "asynchronous",
15]
16
17# Prevent multiple copies of this crate in the same binary.
18# Needed because different copies might get different tick rates, causing
19# wrong delays if the time driver is using one copy and user code is using another.
20# This is especially common when mixing crates from crates.io and git.
21links = "embassy-time-queue"
22
23[dependencies]
24heapless = "0.8"
25embassy-executor = { version = "0.7.0", path = "../embassy-executor" }
26
27[features]
28#! ### Generic Queue
29
30#! By default this crate uses a timer queue implementation that is faster but depends on `embassy-executor`.
31#! It will panic if you try to await any timer when using another executor.
32#!
33#! Alternatively, you can choose to use a "generic" timer queue implementation that works on any executor.
34#! To enable it, enable any of the features below.
35#!
36#! The features also set how many timers are used for the generic queue. At most one
37#! `generic-queue-*` feature can be enabled. If none is enabled, a default of 64 timers is used.
38#!
39#! When using embassy-time-queue-driver from libraries, you should *not* enable any `generic-queue-*` feature, to allow the
40#! end user to pick.
41
42## Generic Queue with 8 timers
43generic-queue-8 = ["_generic-queue"]
44## Generic Queue with 16 timers
45generic-queue-16 = ["_generic-queue"]
46## Generic Queue with 32 timers
47generic-queue-32 = ["_generic-queue"]
48## Generic Queue with 64 timers
49generic-queue-64 = ["_generic-queue"]
50## Generic Queue with 128 timers
51generic-queue-128 = ["_generic-queue"]
52
53_generic-queue = []
54
55[package.metadata.embassy_docs]
56src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-queue-driver-v$VERSION/embassy-time-queue-driver/src/"
57src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-time-queue-driver/src/"
58target = "x86_64-unknown-linux-gnu"
diff --git a/embassy-time-queue-driver/README.md b/embassy-time-queue-driver/README.md
deleted file mode 100644
index b9fb12d94..000000000
--- a/embassy-time-queue-driver/README.md
+++ /dev/null
@@ -1,8 +0,0 @@
1# embassy-time-queue-driver
2
3This crate contains the driver trait used by the [`embassy-time`](https://crates.io/crates/embassy-time) timer queue.
4
5You should rarely need to use this crate directly. Only use it when implementing your own timer queue.
6
7There is two timer queue implementations, one in `embassy-time` enabled by the `generic-queue` feature, and
8another in `embassy-executor` enabled by the `integrated-timers` feature.
diff --git a/embassy-time-queue-driver/build.rs b/embassy-time-queue-driver/build.rs
deleted file mode 100644
index f328e4d9d..000000000
--- a/embassy-time-queue-driver/build.rs
+++ /dev/null
@@ -1 +0,0 @@
1fn main() {}
diff --git a/embassy-time-queue-driver/src/lib.rs b/embassy-time-queue-driver/src/lib.rs
deleted file mode 100644
index 72453f0ea..000000000
--- a/embassy-time-queue-driver/src/lib.rs
+++ /dev/null
@@ -1,20 +0,0 @@
1#![no_std]
2#![doc = include_str!("../README.md")]
3#![warn(missing_docs)]
4
5//! This crate is an implementation detail of `embassy-time-driver`.
6//!
7//! As a HAL user, you should not need to depend on this crate directly.
8//!
9//! As a HAL implementer, you need to depend on this crate if you want to implement a time driver,
10//! but how you should do so is documented in `embassy-time-driver`.
11
12#[cfg(feature = "_generic-queue")]
13pub mod queue_generic;
14#[cfg(not(feature = "_generic-queue"))]
15pub mod queue_integrated;
16
17#[cfg(feature = "_generic-queue")]
18pub use queue_generic::Queue;
19#[cfg(not(feature = "_generic-queue"))]
20pub use queue_integrated::Queue;
diff --git a/embassy-time-queue-driver/src/queue_generic.rs b/embassy-time-queue-driver/src/queue_generic.rs
deleted file mode 100644
index 232035bc6..000000000
--- a/embassy-time-queue-driver/src/queue_generic.rs
+++ /dev/null
@@ -1,146 +0,0 @@
1//! Generic timer queue implementations.
2//!
3//! Time queue drivers may use this to simplify their implementation.
4
5use core::cmp::{min, Ordering};
6use core::task::Waker;
7
8use heapless::Vec;
9
10#[derive(Debug)]
11struct Timer {
12 at: u64,
13 waker: Waker,
14}
15
16impl PartialEq for Timer {
17 fn eq(&self, other: &Self) -> bool {
18 self.at == other.at
19 }
20}
21
22impl Eq for Timer {}
23
24impl PartialOrd for Timer {
25 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
26 self.at.partial_cmp(&other.at)
27 }
28}
29
30impl Ord for Timer {
31 fn cmp(&self, other: &Self) -> Ordering {
32 self.at.cmp(&other.at)
33 }
34}
35
36/// A timer queue with a pre-determined capacity.
37pub struct ConstGenericQueue<const QUEUE_SIZE: usize> {
38 queue: Vec<Timer, QUEUE_SIZE>,
39}
40
41impl<const QUEUE_SIZE: usize> ConstGenericQueue<QUEUE_SIZE> {
42 /// Creates a new timer queue.
43 pub const fn new() -> Self {
44 Self { queue: Vec::new() }
45 }
46
47 /// Schedules a task to run at a specific time, and returns whether any changes were made.
48 ///
49 /// If this function returns `true`, the called should find the next expiration time and set
50 /// a new alarm for that time.
51 pub fn schedule_wake(&mut self, at: u64, waker: &Waker) -> bool {
52 self.queue
53 .iter_mut()
54 .find(|timer| timer.waker.will_wake(waker))
55 .map(|timer| {
56 if timer.at > at {
57 timer.at = at;
58 true
59 } else {
60 false
61 }
62 })
63 .unwrap_or_else(|| {
64 let mut timer = Timer {
65 waker: waker.clone(),
66 at,
67 };
68
69 loop {
70 match self.queue.push(timer) {
71 Ok(()) => break,
72 Err(e) => timer = e,
73 }
74
75 self.queue.pop().unwrap().waker.wake();
76 }
77
78 true
79 })
80 }
81
82 /// Dequeues expired timers and returns the next alarm time.
83 pub fn next_expiration(&mut self, now: u64) -> u64 {
84 let mut next_alarm = u64::MAX;
85
86 let mut i = 0;
87 while i < self.queue.len() {
88 let timer = &self.queue[i];
89 if timer.at <= now {
90 let timer = self.queue.swap_remove(i);
91 timer.waker.wake();
92 } else {
93 next_alarm = min(next_alarm, timer.at);
94 i += 1;
95 }
96 }
97
98 next_alarm
99 }
100}
101
102#[cfg(feature = "generic-queue-8")]
103const QUEUE_SIZE: usize = 8;
104#[cfg(feature = "generic-queue-16")]
105const QUEUE_SIZE: usize = 16;
106#[cfg(feature = "generic-queue-32")]
107const QUEUE_SIZE: usize = 32;
108#[cfg(feature = "generic-queue-64")]
109const QUEUE_SIZE: usize = 64;
110#[cfg(feature = "generic-queue-128")]
111const QUEUE_SIZE: usize = 128;
112#[cfg(not(any(
113 feature = "generic-queue-8",
114 feature = "generic-queue-16",
115 feature = "generic-queue-32",
116 feature = "generic-queue-64",
117 feature = "generic-queue-128"
118)))]
119const QUEUE_SIZE: usize = 64;
120
121/// A timer queue with a pre-determined capacity.
122pub struct Queue {
123 queue: ConstGenericQueue<QUEUE_SIZE>,
124}
125
126impl Queue {
127 /// Creates a new timer queue.
128 pub const fn new() -> Self {
129 Self {
130 queue: ConstGenericQueue::new(),
131 }
132 }
133
134 /// Schedules a task to run at a specific time, and returns whether any changes were made.
135 ///
136 /// If this function returns `true`, the called should find the next expiration time and set
137 /// a new alarm for that time.
138 pub fn schedule_wake(&mut self, at: u64, waker: &Waker) -> bool {
139 self.queue.schedule_wake(at, waker)
140 }
141
142 /// Dequeues expired timers and returns the next alarm time.
143 pub fn next_expiration(&mut self, now: u64) -> u64 {
144 self.queue.next_expiration(now)
145 }
146}
diff --git a/embassy-time-queue-driver/src/queue_integrated.rs b/embassy-time-queue-driver/src/queue_integrated.rs
deleted file mode 100644
index 246cf1d63..000000000
--- a/embassy-time-queue-driver/src/queue_integrated.rs
+++ /dev/null
@@ -1,89 +0,0 @@
1//! Timer queue operations.
2use core::cell::Cell;
3use core::cmp::min;
4use core::task::Waker;
5
6use embassy_executor::raw::TaskRef;
7
8/// A timer queue, with items integrated into tasks.
9pub struct Queue {
10 head: Cell<Option<TaskRef>>,
11}
12
13impl Queue {
14 /// Creates a new timer queue.
15 pub const fn new() -> Self {
16 Self { head: Cell::new(None) }
17 }
18
19 /// Schedules a task to run at a specific time.
20 ///
21 /// If this function returns `true`, the called should find the next expiration time and set
22 /// a new alarm for that time.
23 pub fn schedule_wake(&mut self, at: u64, waker: &Waker) -> bool {
24 let task = embassy_executor::raw::task_from_waker(waker);
25 let item = task.timer_queue_item();
26 if item.next.get().is_none() {
27 // If not in the queue, add it and update.
28 let prev = self.head.replace(Some(task));
29 item.next.set(if prev.is_none() {
30 Some(unsafe { TaskRef::dangling() })
31 } else {
32 prev
33 });
34 item.expires_at.set(at);
35 true
36 } else if at <= item.expires_at.get() {
37 // If expiration is sooner than previously set, update.
38 item.expires_at.set(at);
39 true
40 } else {
41 // Task does not need to be updated.
42 false
43 }
44 }
45
46 /// Dequeues expired timers and returns the next alarm time.
47 ///
48 /// The provided callback will be called for each expired task. Tasks that never expire
49 /// will be removed, but the callback will not be called.
50 pub fn next_expiration(&mut self, now: u64) -> u64 {
51 let mut next_expiration = u64::MAX;
52
53 self.retain(|p| {
54 let item = p.timer_queue_item();
55 let expires = item.expires_at.get();
56
57 if expires <= now {
58 // Timer expired, process task.
59 embassy_executor::raw::wake_task(p);
60 false
61 } else {
62 // Timer didn't yet expire, or never expires.
63 next_expiration = min(next_expiration, expires);
64 expires != u64::MAX
65 }
66 });
67
68 next_expiration
69 }
70
71 fn retain(&self, mut f: impl FnMut(TaskRef) -> bool) {
72 let mut prev = &self.head;
73 while let Some(p) = prev.get() {
74 if unsafe { p == TaskRef::dangling() } {
75 // prev was the last item, stop
76 break;
77 }
78 let item = p.timer_queue_item();
79 if f(p) {
80 // Skip to next
81 prev = &item.next;
82 } else {
83 // Remove it
84 prev.set(item.next.get());
85 item.next.set(None);
86 }
87 }
88 }
89}