aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordiondokter <[email protected]>2025-08-29 14:36:17 +0200
committerDario Nieuwenhuis <[email protected]>2025-09-11 14:45:27 +0200
commit52d178560501a464dba67da89a1570ae9a2cf66c (patch)
tree285b11fe4f91a77789f649377e431414e43f7ac2
parentd6d4df1c768f8ae43ad1339b74d351f4cbad0386 (diff)
Introduce metadata-deadline and let the EDF scheduler use it
-rw-r--r--embassy-executor/Cargo.toml4
-rw-r--r--embassy-executor/src/metadata.rs13
-rw-r--r--embassy-executor/src/raw/deadline.rs18
-rw-r--r--embassy-executor/src/raw/mod.rs19
-rw-r--r--embassy-executor/src/raw/run_queue.rs5
5 files changed, 36 insertions, 23 deletions
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index 290e67bce..2de36d22d 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -118,6 +118,8 @@ arch-spin = ["_arch"]
118 118
119## Enable the `name` field in task metadata. 119## Enable the `name` field in task metadata.
120metadata-name = ["embassy-executor-macros/metadata-name"] 120metadata-name = ["embassy-executor-macros/metadata-name"]
121## Enable the `deadline` field in task metadata.
122metadata-deadline = []
121 123
122#! ### Executor 124#! ### Executor
123 125
@@ -133,4 +135,4 @@ _any_trace = []
133 135
134## Enable "Earliest Deadline First" Scheduler, using soft-realtime "deadlines" to prioritize 136## Enable "Earliest Deadline First" Scheduler, using soft-realtime "deadlines" to prioritize
135## tasks based on the remaining time before their deadline. Adds some overhead. 137## tasks based on the remaining time before their deadline. Adds some overhead.
136edf-scheduler = ["dep:embassy-time-driver"] 138edf-scheduler = ["dep:embassy-time-driver", "metadata-deadline"]
diff --git a/embassy-executor/src/metadata.rs b/embassy-executor/src/metadata.rs
index f92c9b37c..fd8095629 100644
--- a/embassy-executor/src/metadata.rs
+++ b/embassy-executor/src/metadata.rs
@@ -12,6 +12,8 @@ use crate::raw;
12pub struct Metadata { 12pub struct Metadata {
13 #[cfg(feature = "metadata-name")] 13 #[cfg(feature = "metadata-name")]
14 name: Mutex<Cell<Option<&'static str>>>, 14 name: Mutex<Cell<Option<&'static str>>>,
15 #[cfg(feature = "metadata-deadline")]
16 deadline: raw::Deadline,
15} 17}
16 18
17impl Metadata { 19impl Metadata {
@@ -19,6 +21,10 @@ impl Metadata {
19 Self { 21 Self {
20 #[cfg(feature = "metadata-name")] 22 #[cfg(feature = "metadata-name")]
21 name: Mutex::new(Cell::new(None)), 23 name: Mutex::new(Cell::new(None)),
24 // NOTE: The deadline is set to zero to allow the initializer to reside in `.bss`. This
25 // will be lazily initalized in `initialize_impl`
26 #[cfg(feature = "metadata-deadline")]
27 deadline: raw::Deadline::new_unset(),
22 } 28 }
23 } 29 }
24 30
@@ -52,4 +58,11 @@ impl Metadata {
52 pub fn set_name(&self, name: &'static str) { 58 pub fn set_name(&self, name: &'static str) {
53 critical_section::with(|cs| self.name.borrow(cs).set(Some(name))) 59 critical_section::with(|cs| self.name.borrow(cs).set(Some(name)))
54 } 60 }
61
62 /// Earliest Deadline First scheduler Deadline. This field should not be accessed
63 /// outside the context of the task itself as it being polled by the executor.
64 #[cfg(feature = "metadata-deadline")]
65 pub fn deadline(&self) -> &raw::Deadline {
66 &self.deadline
67 }
55} 68}
diff --git a/embassy-executor/src/raw/deadline.rs b/embassy-executor/src/raw/deadline.rs
index cbb379b82..5b585195d 100644
--- a/embassy-executor/src/raw/deadline.rs
+++ b/embassy-executor/src/raw/deadline.rs
@@ -62,7 +62,7 @@ impl Deadline {
62 pub fn set_current_task_deadline(instant_ticks: u64) -> impl Future<Output = ()> { 62 pub fn set_current_task_deadline(instant_ticks: u64) -> impl Future<Output = ()> {
63 poll_fn(move |cx| { 63 poll_fn(move |cx| {
64 let task = super::task_from_waker(cx.waker()); 64 let task = super::task_from_waker(cx.waker());
65 task.header().deadline.set(instant_ticks); 65 task.header().metadata.deadline().set(instant_ticks);
66 Poll::Ready(()) 66 Poll::Ready(())
67 }) 67 })
68 } 68 }
@@ -87,7 +87,7 @@ impl Deadline {
87 // reasons later. 87 // reasons later.
88 let deadline = now.saturating_add(duration_ticks); 88 let deadline = now.saturating_add(duration_ticks);
89 89
90 task.header().deadline.set(deadline); 90 task.header().metadata.deadline().set(deadline);
91 91
92 Poll::Ready(Deadline::new(deadline)) 92 Poll::Ready(Deadline::new(deadline))
93 }) 93 })
@@ -109,10 +109,10 @@ impl Deadline {
109 #[must_use = "Setting deadline must be polled to be effective"] 109 #[must_use = "Setting deadline must be polled to be effective"]
110 pub fn increment_current_task_deadline(increment_ticks: u64) -> impl Future<Output = Deadline> { 110 pub fn increment_current_task_deadline(increment_ticks: u64) -> impl Future<Output = Deadline> {
111 poll_fn(move |cx| { 111 poll_fn(move |cx| {
112 let task = super::task_from_waker(cx.waker()); 112 let task_header = super::task_from_waker(cx.waker()).header();
113 113
114 // Get the last value 114 // Get the last value
115 let last = task.header().deadline.instant_ticks(); 115 let last = task_header.metadata.deadline().instant_ticks();
116 116
117 // Since ticks is a u64, saturating add is PROBABLY overly cautious, leave 117 // Since ticks is a u64, saturating add is PROBABLY overly cautious, leave
118 // it for now, we can probably make this wrapping_add for performance 118 // it for now, we can probably make this wrapping_add for performance
@@ -120,7 +120,7 @@ impl Deadline {
120 let deadline = last.saturating_add(increment_ticks); 120 let deadline = last.saturating_add(increment_ticks);
121 121
122 // Store the new value 122 // Store the new value
123 task.header().deadline.set(deadline); 123 task_header.metadata.deadline().set(deadline);
124 124
125 Poll::Ready(Deadline::new(deadline)) 125 Poll::Ready(Deadline::new(deadline))
126 }) 126 })
@@ -134,7 +134,7 @@ impl Deadline {
134 poll_fn(move |cx| { 134 poll_fn(move |cx| {
135 let task = super::task_from_waker(cx.waker()); 135 let task = super::task_from_waker(cx.waker());
136 136
137 let deadline = task.header().deadline.instant_ticks(); 137 let deadline = task.header().metadata.deadline().instant_ticks();
138 Poll::Ready(Self::new(deadline)) 138 Poll::Ready(Self::new(deadline))
139 }) 139 })
140 } 140 }
@@ -146,12 +146,12 @@ impl Deadline {
146 #[must_use = "Clearing deadline must be polled to be effective"] 146 #[must_use = "Clearing deadline must be polled to be effective"]
147 pub fn clear_current_task_deadline() -> impl Future<Output = Self> { 147 pub fn clear_current_task_deadline() -> impl Future<Output = Self> {
148 poll_fn(move |cx| { 148 poll_fn(move |cx| {
149 let task = super::task_from_waker(cx.waker()); 149 let task_header = super::task_from_waker(cx.waker()).header();
150 150
151 // get the old value 151 // get the old value
152 let deadline = task.header().deadline.instant_ticks(); 152 let deadline = task_header.metadata.deadline().instant_ticks();
153 // Store the default value 153 // Store the default value
154 task.header().deadline.set(Self::UNSET_DEADLINE_TICKS); 154 task_header.metadata.deadline().set(Self::UNSET_DEADLINE_TICKS);
155 155
156 Poll::Ready(Self::new(deadline)) 156 Poll::Ready(Self::new(deadline))
157 }) 157 })
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index be2c5ee28..f93bfdef9 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -26,7 +26,7 @@ pub(crate) mod util;
26#[cfg_attr(feature = "turbowakers", path = "waker_turbo.rs")] 26#[cfg_attr(feature = "turbowakers", path = "waker_turbo.rs")]
27mod waker; 27mod waker;
28 28
29#[cfg(feature = "edf-scheduler")] 29#[cfg(feature = "metadata-deadline")]
30mod deadline; 30mod deadline;
31 31
32use core::future::Future; 32use core::future::Future;
@@ -43,7 +43,7 @@ use embassy_executor_timer_queue::TimerQueueItem;
43#[cfg(feature = "arch-avr")] 43#[cfg(feature = "arch-avr")]
44use portable_atomic::AtomicPtr; 44use portable_atomic::AtomicPtr;
45 45
46#[cfg(feature = "edf-scheduler")] 46#[cfg(feature = "metadata-deadline")]
47pub use deadline::Deadline; 47pub use deadline::Deadline;
48#[cfg(feature = "arch-avr")] 48#[cfg(feature = "arch-avr")]
49use portable_atomic::AtomicPtr; 49use portable_atomic::AtomicPtr;
@@ -103,11 +103,6 @@ pub(crate) struct TaskHeader {
103 pub(crate) state: State, 103 pub(crate) state: State,
104 pub(crate) run_queue_item: RunQueueItem, 104 pub(crate) run_queue_item: RunQueueItem,
105 105
106 /// Earliest Deadline First scheduler Deadline. This field should not be accessed
107 /// outside the context of the task itself as it being polled by the executor.
108 #[cfg(feature = "edf-scheduler")]
109 pub(crate) deadline: Deadline,
110
111 pub(crate) executor: AtomicPtr<SyncExecutor>, 106 pub(crate) executor: AtomicPtr<SyncExecutor>,
112 poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>, 107 poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>,
113 108
@@ -212,10 +207,6 @@ impl<F: Future + 'static> TaskStorage<F> {
212 raw: TaskHeader { 207 raw: TaskHeader {
213 state: State::new(), 208 state: State::new(),
214 run_queue_item: RunQueueItem::new(), 209 run_queue_item: RunQueueItem::new(),
215 // NOTE: The deadline is set to zero to allow the initializer to reside in `.bss`. This
216 // will be lazily initalized in `initialize_impl`
217 #[cfg(feature = "edf-scheduler")]
218 deadline: Deadline::new_unset(),
219 executor: AtomicPtr::new(core::ptr::null_mut()), 210 executor: AtomicPtr::new(core::ptr::null_mut()),
220 // Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss` 211 // Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss`
221 poll_fn: SyncUnsafeCell::new(None), 212 poll_fn: SyncUnsafeCell::new(None),
@@ -315,7 +306,11 @@ impl<F: Future + 'static> AvailableTask<F> {
315 // By default, deadlines are set to the maximum value, so that any task WITH 306 // By default, deadlines are set to the maximum value, so that any task WITH
316 // a set deadline will ALWAYS be scheduled BEFORE a task WITHOUT a set deadline 307 // a set deadline will ALWAYS be scheduled BEFORE a task WITHOUT a set deadline
317 #[cfg(feature = "edf-scheduler")] 308 #[cfg(feature = "edf-scheduler")]
318 self.task.raw.deadline.set(deadline::Deadline::UNSET_DEADLINE_TICKS); 309 self.task
310 .raw
311 .metadata
312 .deadline()
313 .set(deadline::Deadline::UNSET_DEADLINE_TICKS);
319 314
320 let task = TaskRef::new(self.task); 315 let task = TaskRef::new(self.task);
321 316
diff --git a/embassy-executor/src/raw/run_queue.rs b/embassy-executor/src/raw/run_queue.rs
index e8a046a48..978ca082a 100644
--- a/embassy-executor/src/raw/run_queue.rs
+++ b/embassy-executor/src/raw/run_queue.rs
@@ -109,7 +109,10 @@ impl RunQueue {
109 #[cfg(feature = "edf-scheduler")] 109 #[cfg(feature = "edf-scheduler")]
110 pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) { 110 pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
111 let mut sorted = SortedList::<TaskHeader>::new_with_cmp(|lhs, rhs| { 111 let mut sorted = SortedList::<TaskHeader>::new_with_cmp(|lhs, rhs| {
112 lhs.deadline.instant_ticks().cmp(&rhs.deadline.instant_ticks()) 112 lhs.metadata
113 .deadline()
114 .instant_ticks()
115 .cmp(&rhs.metadata.deadline().instant_ticks())
113 }); 116 });
114 117
115 loop { 118 loop {