aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src
diff options
context:
space:
mode:
authorDion Dokter <[email protected]>2025-09-08 11:40:34 +0200
committerDario Nieuwenhuis <[email protected]>2025-09-11 14:45:40 +0200
commit401fac6ea95b6dd16492d784f99f07fb9a1b318b (patch)
tree2772faca81917e5ef47e8bffe1a9d33aff313d8b /embassy-executor/src
parentadb0c3e947dc72027a121a74a700df10fc9e2337 (diff)
Make requested API changes
Diffstat (limited to 'embassy-executor/src')
-rw-r--r--embassy-executor/src/metadata.rs64
-rw-r--r--embassy-executor/src/raw/deadline.rs109
-rw-r--r--embassy-executor/src/raw/mod.rs6
-rw-r--r--embassy-executor/src/raw/run_queue.rs6
4 files changed, 65 insertions, 120 deletions
diff --git a/embassy-executor/src/metadata.rs b/embassy-executor/src/metadata.rs
index fd8095629..81c5afafb 100644
--- a/embassy-executor/src/metadata.rs
+++ b/embassy-executor/src/metadata.rs
@@ -7,12 +7,14 @@ use core::task::Poll;
7use critical_section::Mutex; 7use critical_section::Mutex;
8 8
9use crate::raw; 9use crate::raw;
10#[cfg(feature = "scheduler-deadline")]
11use crate::raw::Deadline;
10 12
11/// Metadata associated with a task. 13/// Metadata associated with a task.
12pub struct Metadata { 14pub struct Metadata {
13 #[cfg(feature = "metadata-name")] 15 #[cfg(feature = "metadata-name")]
14 name: Mutex<Cell<Option<&'static str>>>, 16 name: Mutex<Cell<Option<&'static str>>>,
15 #[cfg(feature = "metadata-deadline")] 17 #[cfg(feature = "scheduler-deadline")]
16 deadline: raw::Deadline, 18 deadline: raw::Deadline,
17} 19}
18 20
@@ -23,7 +25,7 @@ impl Metadata {
23 name: Mutex::new(Cell::new(None)), 25 name: Mutex::new(Cell::new(None)),
24 // NOTE: The deadline is set to zero to allow the initializer to reside in `.bss`. This 26 // NOTE: The deadline is set to zero to allow the initializer to reside in `.bss`. This
25 // will be lazily initalized in `initialize_impl` 27 // will be lazily initalized in `initialize_impl`
26 #[cfg(feature = "metadata-deadline")] 28 #[cfg(feature = "scheduler-deadline")]
27 deadline: raw::Deadline::new_unset(), 29 deadline: raw::Deadline::new_unset(),
28 } 30 }
29 } 31 }
@@ -59,10 +61,62 @@ impl Metadata {
59 critical_section::with(|cs| self.name.borrow(cs).set(Some(name))) 61 critical_section::with(|cs| self.name.borrow(cs).set(Some(name)))
60 } 62 }
61 63
62 /// Earliest Deadline First scheduler Deadline. This field should not be accessed 64 /// Get this task's deadline.
63 /// outside the context of the task itself as it being polled by the executor. 65 #[cfg(feature = "scheduler-deadline")]
64 #[cfg(feature = "metadata-deadline")]
65 pub fn deadline(&self) -> &raw::Deadline { 66 pub fn deadline(&self) -> &raw::Deadline {
66 &self.deadline 67 &self.deadline
67 } 68 }
69
70 /// Set this task's deadline.
71 ///
72 /// This method does NOT check whether the deadline has already passed.
73 #[cfg(feature = "scheduler-deadline")]
74 pub fn set_deadline(&self, instant_ticks: u64) {
75 self.deadline.set(instant_ticks);
76 }
77
78 /// Remove this task's deadline.
79 /// This brings it back to the defaul where it's not scheduled ahead of other tasks.
80 #[cfg(feature = "scheduler-deadline")]
81 pub fn unset_deadline(&self) {
82 self.deadline.set(Deadline::UNSET_DEADLINE_TICKS);
83 }
84
85 /// Set this task's deadline `duration_ticks` in the future from when
86 /// this future is polled. This deadline is saturated to the max tick value.
87 ///
88 /// Analogous to `Timer::after`.
89 #[cfg(all(feature = "scheduler-deadline", feature = "embassy-time-driver"))]
90 pub fn set_deadline_after(&self, duration_ticks: u64) {
91 let now = embassy_time_driver::now();
92
93 // Since ticks is a u64, saturating add is PROBABLY overly cautious, leave
94 // it for now, we can probably make this wrapping_add for performance
95 // reasons later.
96 let deadline = now.saturating_add(duration_ticks);
97
98 self.set_deadline(deadline);
99 }
100
101 /// Set the this task's deadline `increment_ticks` from the previous deadline.
102 ///
103 /// This deadline is saturated to the max tick value.
104 ///
105 /// Note that by default (unless otherwise set), tasks start life with the deadline
106 /// not set, which means this method will have no effect.
107 ///
108 /// Analogous to one increment of `Ticker::every().next()`.
109 ///
110 /// Returns the deadline that was set.
111 #[cfg(feature = "scheduler-deadline")]
112 pub fn increment_deadline(&self, duration_ticks: u64) {
113 let last = self.deadline().instant_ticks();
114
115 // Since ticks is a u64, saturating add is PROBABLY overly cautious, leave
116 // it for now, we can probably make this wrapping_add for performance
117 // reasons later.
118 let deadline = last.saturating_add(duration_ticks);
119
120 self.set_deadline(deadline);
121 }
68} 122}
diff --git a/embassy-executor/src/raw/deadline.rs b/embassy-executor/src/raw/deadline.rs
index 5b585195d..d08dd06ed 100644
--- a/embassy-executor/src/raw/deadline.rs
+++ b/embassy-executor/src/raw/deadline.rs
@@ -1,6 +1,4 @@
1use core::future::{poll_fn, Future};
2use core::sync::atomic::{AtomicU32, Ordering}; 1use core::sync::atomic::{AtomicU32, Ordering};
3use core::task::Poll;
4 2
5/// A type for interacting with the deadline of the current task 3/// A type for interacting with the deadline of the current task
6/// 4///
@@ -49,111 +47,4 @@ impl Deadline {
49 pub fn is_unset(&self) -> bool { 47 pub fn is_unset(&self) -> bool {
50 self.instant_ticks() == Self::UNSET_DEADLINE_TICKS 48 self.instant_ticks() == Self::UNSET_DEADLINE_TICKS
51 } 49 }
52
53 /// Set the current task's deadline at exactly `instant_ticks`
54 ///
55 /// This method is a future in order to access the currently executing task's
56 /// header which contains the deadline.
57 ///
58 /// Analogous to `Timer::at`.
59 ///
60 /// This method does NOT check whether the deadline has already passed.
61 #[must_use = "Setting deadline must be polled to be effective"]
62 pub fn set_current_task_deadline(instant_ticks: u64) -> impl Future<Output = ()> {
63 poll_fn(move |cx| {
64 let task = super::task_from_waker(cx.waker());
65 task.header().metadata.deadline().set(instant_ticks);
66 Poll::Ready(())
67 })
68 }
69
70 /// Set the current task's deadline `duration_ticks` in the future from when
71 /// this future is polled. This deadline is saturated to the max tick value.
72 ///
73 /// This method is a future in order to access the currently executing task's
74 /// header which contains the deadline.
75 ///
76 /// Analogous to `Timer::after`.
77 ///
78 /// Returns the deadline that was set.
79 #[must_use = "Setting deadline must be polled to be effective"]
80 pub fn set_current_task_deadline_after(duration_ticks: u64) -> impl Future<Output = Deadline> {
81 poll_fn(move |cx| {
82 let task = super::task_from_waker(cx.waker());
83 let now = embassy_time_driver::now();
84
85 // Since ticks is a u64, saturating add is PROBABLY overly cautious, leave
86 // it for now, we can probably make this wrapping_add for performance
87 // reasons later.
88 let deadline = now.saturating_add(duration_ticks);
89
90 task.header().metadata.deadline().set(deadline);
91
92 Poll::Ready(Deadline::new(deadline))
93 })
94 }
95
96 /// Set the current task's deadline `increment_ticks` from the previous deadline.
97 ///
98 /// This deadline is saturated to the max tick value.
99 ///
100 /// Note that by default (unless otherwise set), tasks start life with the deadline
101 /// u64::MAX, which means this method will have no effect.
102 ///
103 /// This method is a future in order to access the currently executing task's
104 /// header which contains the deadline
105 ///
106 /// Analogous to one increment of `Ticker::every().next()`.
107 ///
108 /// Returns the deadline that was set.
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> {
111 poll_fn(move |cx| {
112 let task_header = super::task_from_waker(cx.waker()).header();
113
114 // Get the last value
115 let last = task_header.metadata.deadline().instant_ticks();
116
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
119 // reasons later.
120 let deadline = last.saturating_add(increment_ticks);
121
122 // Store the new value
123 task_header.metadata.deadline().set(deadline);
124
125 Poll::Ready(Deadline::new(deadline))
126 })
127 }
128
129 /// Get the current task's deadline as a tick value.
130 ///
131 /// This method is a future in order to access the currently executing task's
132 /// header which contains the deadline
133 pub fn get_current_task_deadline() -> impl Future<Output = Self> {
134 poll_fn(move |cx| {
135 let task = super::task_from_waker(cx.waker());
136
137 let deadline = task.header().metadata.deadline().instant_ticks();
138 Poll::Ready(Self::new(deadline))
139 })
140 }
141
142 /// Clear the current task's deadline, returning the previous value.
143 ///
144 /// This sets the deadline to the default value of `u64::MAX`, meaning all
145 /// tasks with set deadlines will be scheduled BEFORE this task.
146 #[must_use = "Clearing deadline must be polled to be effective"]
147 pub fn clear_current_task_deadline() -> impl Future<Output = Self> {
148 poll_fn(move |cx| {
149 let task_header = super::task_from_waker(cx.waker()).header();
150
151 // get the old value
152 let deadline = task_header.metadata.deadline().instant_ticks();
153 // Store the default value
154 task_header.metadata.deadline().set(Self::UNSET_DEADLINE_TICKS);
155
156 Poll::Ready(Self::new(deadline))
157 })
158 }
159} 50}
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index 86ee86842..6a9dd9749 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 = "metadata-deadline")] 29#[cfg(feature = "scheduler-deadline")]
30mod deadline; 30mod deadline;
31 31
32use core::future::Future; 32use core::future::Future;
@@ -39,7 +39,7 @@ use core::sync::atomic::AtomicPtr;
39use core::sync::atomic::Ordering; 39use core::sync::atomic::Ordering;
40use core::task::{Context, Poll, Waker}; 40use core::task::{Context, Poll, Waker};
41 41
42#[cfg(feature = "metadata-deadline")] 42#[cfg(feature = "scheduler-deadline")]
43pub use deadline::Deadline; 43pub use deadline::Deadline;
44use embassy_executor_timer_queue::TimerQueueItem; 44use embassy_executor_timer_queue::TimerQueueItem;
45#[cfg(feature = "arch-avr")] 45#[cfg(feature = "arch-avr")]
@@ -302,7 +302,7 @@ impl<F: Future + 'static> AvailableTask<F> {
302 302
303 // By default, deadlines are set to the maximum value, so that any task WITH 303 // By default, deadlines are set to the maximum value, so that any task WITH
304 // a set deadline will ALWAYS be scheduled BEFORE a task WITHOUT a set deadline 304 // a set deadline will ALWAYS be scheduled BEFORE a task WITHOUT a set deadline
305 #[cfg(feature = "edf-scheduler")] 305 #[cfg(feature = "scheduler-deadline")]
306 self.task 306 self.task
307 .raw 307 .raw
308 .metadata 308 .metadata
diff --git a/embassy-executor/src/raw/run_queue.rs b/embassy-executor/src/raw/run_queue.rs
index 978ca082a..29c977226 100644
--- a/embassy-executor/src/raw/run_queue.rs
+++ b/embassy-executor/src/raw/run_queue.rs
@@ -2,7 +2,7 @@ use core::ptr::{addr_of_mut, NonNull};
2 2
3use cordyceps::sorted_list::Links; 3use cordyceps::sorted_list::Links;
4use cordyceps::Linked; 4use cordyceps::Linked;
5#[cfg(feature = "edf-scheduler")] 5#[cfg(feature = "scheduler-deadline")]
6use cordyceps::SortedList; 6use cordyceps::SortedList;
7 7
8#[cfg(target_has_atomic = "ptr")] 8#[cfg(target_has_atomic = "ptr")]
@@ -83,7 +83,7 @@ impl RunQueue {
83 /// Empty the queue, then call `on_task` for each task that was in the queue. 83 /// Empty the queue, then call `on_task` for each task that was in the queue.
84 /// NOTE: It is OK for `on_task` to enqueue more tasks. In this case they're left in the queue 84 /// NOTE: It is OK for `on_task` to enqueue more tasks. In this case they're left in the queue
85 /// and will be processed by the *next* call to `dequeue_all`, *not* the current one. 85 /// and will be processed by the *next* call to `dequeue_all`, *not* the current one.
86 #[cfg(not(feature = "edf-scheduler"))] 86 #[cfg(not(feature = "scheduler-deadline"))]
87 pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) { 87 pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
88 let taken = self.stack.take_all(); 88 let taken = self.stack.take_all();
89 for taskref in taken { 89 for taskref in taken {
@@ -106,7 +106,7 @@ impl RunQueue {
106 /// 106 ///
107 /// This process will repeat until the local `sorted` queue AND the global 107 /// This process will repeat until the local `sorted` queue AND the global
108 /// runqueue are both empty, at which point this function will return. 108 /// runqueue are both empty, at which point this function will return.
109 #[cfg(feature = "edf-scheduler")] 109 #[cfg(feature = "scheduler-deadline")]
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.metadata 112 lhs.metadata