diff options
| author | Dion Dokter <[email protected]> | 2025-07-15 13:40:30 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2025-09-11 14:45:06 +0200 |
| commit | 3f606b28f3b32e9e3b9a9f136eeef52828a78512 (patch) | |
| tree | 640fec12732e7104516c9edbd79261d214887f96 /embassy-executor/src/raw | |
| parent | b5c9e721009fd4331cdc1ce58a07698eb54f2959 (diff) | |
Change deadline to use internal atomics
Diffstat (limited to 'embassy-executor/src/raw')
| -rw-r--r-- | embassy-executor/src/raw/deadline.rs | 101 | ||||
| -rw-r--r-- | embassy-executor/src/raw/mod.rs | 4 | ||||
| -rw-r--r-- | embassy-executor/src/raw/run_queue.rs | 8 |
3 files changed, 55 insertions, 58 deletions
diff --git a/embassy-executor/src/raw/deadline.rs b/embassy-executor/src/raw/deadline.rs index 0fb22a7ce..a61852612 100644 --- a/embassy-executor/src/raw/deadline.rs +++ b/embassy-executor/src/raw/deadline.rs | |||
| @@ -1,15 +1,41 @@ | |||
| 1 | use core::future::{poll_fn, Future}; | 1 | use core::future::{poll_fn, Future}; |
| 2 | use core::sync::atomic::{AtomicU32, Ordering}; | ||
| 2 | use core::task::Poll; | 3 | use core::task::Poll; |
| 3 | 4 | ||
| 4 | /// A type for interacting with the deadline of the current task | 5 | /// A type for interacting with the deadline of the current task |
| 5 | /// | 6 | /// |
| 6 | /// Requires the `edf-scheduler` feature | 7 | /// Requires the `edf-scheduler` feature |
| 7 | pub struct Deadline { | 8 | pub struct Deadline { |
| 8 | /// Deadline value in ticks, same time base and ticks as `embassy-time` | 9 | instant_ticks_hi: AtomicU32, |
| 9 | pub instant_ticks: u64, | 10 | instant_ticks_lo: AtomicU32, |
| 10 | } | 11 | } |
| 11 | 12 | ||
| 12 | impl Deadline { | 13 | impl Deadline { |
| 14 | pub(crate) const fn new(instant_ticks: u64) -> Self { | ||
| 15 | Self { | ||
| 16 | instant_ticks_hi: AtomicU32::new((instant_ticks >> 32) as u32), | ||
| 17 | instant_ticks_lo: AtomicU32::new(instant_ticks as u32), | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 21 | pub(crate) const fn new_unset() -> Self { | ||
| 22 | Self::new(Self::UNSET_DEADLINE_TICKS) | ||
| 23 | } | ||
| 24 | |||
| 25 | pub(crate) fn set(&self, instant_ticks: u64) { | ||
| 26 | self.instant_ticks_hi | ||
| 27 | .store((instant_ticks >> 32) as u32, Ordering::Relaxed); | ||
| 28 | self.instant_ticks_lo.store(instant_ticks as u32, Ordering::Relaxed); | ||
| 29 | } | ||
| 30 | |||
| 31 | /// Deadline value in ticks, same time base and ticks as `embassy-time` | ||
| 32 | pub fn instant_ticks(&self) -> u64 { | ||
| 33 | let hi = self.instant_ticks_hi.load(Ordering::Relaxed) as u64; | ||
| 34 | let lo = self.instant_ticks_lo.load(Ordering::Relaxed) as u64; | ||
| 35 | |||
| 36 | (hi << 32) | lo | ||
| 37 | } | ||
| 38 | |||
| 13 | /// Sentinel value representing an "unset" deadline, which has lower priority | 39 | /// Sentinel value representing an "unset" deadline, which has lower priority |
| 14 | /// than any other set deadline value | 40 | /// than any other set deadline value |
| 15 | pub const UNSET_DEADLINE_TICKS: u64 = u64::MAX; | 41 | pub const UNSET_DEADLINE_TICKS: u64 = u64::MAX; |
| @@ -17,7 +43,7 @@ impl Deadline { | |||
| 17 | /// Does the given Deadline represent an "unset" deadline? | 43 | /// Does the given Deadline represent an "unset" deadline? |
| 18 | #[inline] | 44 | #[inline] |
| 19 | pub fn is_unset(&self) -> bool { | 45 | pub fn is_unset(&self) -> bool { |
| 20 | self.instant_ticks == Self::UNSET_DEADLINE_TICKS | 46 | self.instant_ticks() == Self::UNSET_DEADLINE_TICKS |
| 21 | } | 47 | } |
| 22 | 48 | ||
| 23 | /// Set the current task's deadline at exactly `instant_ticks` | 49 | /// Set the current task's deadline at exactly `instant_ticks` |
| @@ -32,11 +58,7 @@ impl Deadline { | |||
| 32 | pub fn set_current_task_deadline(instant_ticks: u64) -> impl Future<Output = ()> { | 58 | pub fn set_current_task_deadline(instant_ticks: u64) -> impl Future<Output = ()> { |
| 33 | poll_fn(move |cx| { | 59 | poll_fn(move |cx| { |
| 34 | let task = super::task_from_waker(cx.waker()); | 60 | let task = super::task_from_waker(cx.waker()); |
| 35 | // SAFETY: A task can only modify its own deadline, while the task is being | 61 | task.header().deadline.set(instant_ticks); |
| 36 | // polled, meaning that there cannot be concurrent access to the deadline. | ||
| 37 | unsafe { | ||
| 38 | task.header().deadline.set(instant_ticks); | ||
| 39 | } | ||
| 40 | Poll::Ready(()) | 62 | Poll::Ready(()) |
| 41 | }) | 63 | }) |
| 42 | } | 64 | } |
| @@ -61,14 +83,9 @@ impl Deadline { | |||
| 61 | // reasons later. | 83 | // reasons later. |
| 62 | let deadline = now.saturating_add(duration_ticks); | 84 | let deadline = now.saturating_add(duration_ticks); |
| 63 | 85 | ||
| 64 | // SAFETY: A task can only modify its own deadline, while the task is being | 86 | task.header().deadline.set(deadline); |
| 65 | // polled, meaning that there cannot be concurrent access to the deadline. | 87 | |
| 66 | unsafe { | 88 | Poll::Ready(Deadline::new(deadline)) |
| 67 | task.header().deadline.set(deadline); | ||
| 68 | } | ||
| 69 | Poll::Ready(Deadline { | ||
| 70 | instant_ticks: deadline, | ||
| 71 | }) | ||
| 72 | }) | 89 | }) |
| 73 | } | 90 | } |
| 74 | 91 | ||
| @@ -90,24 +107,18 @@ impl Deadline { | |||
| 90 | poll_fn(move |cx| { | 107 | poll_fn(move |cx| { |
| 91 | let task = super::task_from_waker(cx.waker()); | 108 | let task = super::task_from_waker(cx.waker()); |
| 92 | 109 | ||
| 93 | // SAFETY: A task can only modify its own deadline, while the task is being | 110 | // Get the last value |
| 94 | // polled, meaning that there cannot be concurrent access to the deadline. | 111 | let last = task.header().deadline.instant_ticks(); |
| 95 | unsafe { | ||
| 96 | // Get the last value | ||
| 97 | let last = task.header().deadline.get(); | ||
| 98 | 112 | ||
| 99 | // Since ticks is a u64, saturating add is PROBABLY overly cautious, leave | 113 | // Since ticks is a u64, saturating add is PROBABLY overly cautious, leave |
| 100 | // it for now, we can probably make this wrapping_add for performance | 114 | // it for now, we can probably make this wrapping_add for performance |
| 101 | // reasons later. | 115 | // reasons later. |
| 102 | let deadline = last.saturating_add(increment_ticks); | 116 | let deadline = last.saturating_add(increment_ticks); |
| 103 | 117 | ||
| 104 | // Store the new value | 118 | // Store the new value |
| 105 | task.header().deadline.set(deadline); | 119 | task.header().deadline.set(deadline); |
| 106 | 120 | ||
| 107 | Poll::Ready(Deadline { | 121 | Poll::Ready(Deadline::new(deadline)) |
| 108 | instant_ticks: deadline, | ||
| 109 | }) | ||
| 110 | } | ||
| 111 | }) | 122 | }) |
| 112 | } | 123 | } |
| 113 | 124 | ||
| @@ -119,12 +130,8 @@ impl Deadline { | |||
| 119 | poll_fn(move |cx| { | 130 | poll_fn(move |cx| { |
| 120 | let task = super::task_from_waker(cx.waker()); | 131 | let task = super::task_from_waker(cx.waker()); |
| 121 | 132 | ||
| 122 | // SAFETY: A task can only modify its own deadline, while the task is being | 133 | let deadline = task.header().deadline.instant_ticks(); |
| 123 | // polled, meaning that there cannot be concurrent access to the deadline. | 134 | Poll::Ready(Self::new(deadline)) |
| 124 | let deadline = unsafe { task.header().deadline.get() }; | ||
| 125 | Poll::Ready(Self { | ||
| 126 | instant_ticks: deadline, | ||
| 127 | }) | ||
| 128 | }) | 135 | }) |
| 129 | } | 136 | } |
| 130 | 137 | ||
| @@ -137,20 +144,12 @@ impl Deadline { | |||
| 137 | poll_fn(move |cx| { | 144 | poll_fn(move |cx| { |
| 138 | let task = super::task_from_waker(cx.waker()); | 145 | let task = super::task_from_waker(cx.waker()); |
| 139 | 146 | ||
| 140 | // SAFETY: A task can only modify its own deadline, while the task is being | 147 | // get the old value |
| 141 | // polled, meaning that there cannot be concurrent access to the deadline. | 148 | let deadline = task.header().deadline.instant_ticks(); |
| 142 | let deadline = unsafe { | 149 | // Store the default value |
| 143 | // get the old value | 150 | task.header().deadline.set(Self::UNSET_DEADLINE_TICKS); |
| 144 | let d = task.header().deadline.get(); | 151 | |
| 145 | // Store the default value | 152 | Poll::Ready(Self::new(deadline)) |
| 146 | task.header().deadline.set(Self::UNSET_DEADLINE_TICKS); | ||
| 147 | // return the old value | ||
| 148 | d | ||
| 149 | }; | ||
| 150 | |||
| 151 | Poll::Ready(Self { | ||
| 152 | instant_ticks: deadline, | ||
| 153 | }) | ||
| 154 | }) | 153 | }) |
| 155 | } | 154 | } |
| 156 | } | 155 | } |
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index cc43690cb..be2c5ee28 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs | |||
| @@ -106,7 +106,7 @@ pub(crate) struct TaskHeader { | |||
| 106 | /// Earliest Deadline First scheduler Deadline. This field should not be accessed | 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. | 107 | /// outside the context of the task itself as it being polled by the executor. |
| 108 | #[cfg(feature = "edf-scheduler")] | 108 | #[cfg(feature = "edf-scheduler")] |
| 109 | pub(crate) deadline: SyncUnsafeCell<u64>, | 109 | pub(crate) deadline: Deadline, |
| 110 | 110 | ||
| 111 | pub(crate) executor: AtomicPtr<SyncExecutor>, | 111 | pub(crate) executor: AtomicPtr<SyncExecutor>, |
| 112 | poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>, | 112 | poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>, |
| @@ -215,7 +215,7 @@ impl<F: Future + 'static> TaskStorage<F> { | |||
| 215 | // NOTE: The deadline is set to zero to allow the initializer to reside in `.bss`. This | 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` | 216 | // will be lazily initalized in `initialize_impl` |
| 217 | #[cfg(feature = "edf-scheduler")] | 217 | #[cfg(feature = "edf-scheduler")] |
| 218 | deadline: SyncUnsafeCell::new(0u64), | 218 | deadline: Deadline::new_unset(), |
| 219 | executor: AtomicPtr::new(core::ptr::null_mut()), | 219 | executor: AtomicPtr::new(core::ptr::null_mut()), |
| 220 | // Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss` | 220 | // Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss` |
| 221 | poll_fn: SyncUnsafeCell::new(None), | 221 | poll_fn: SyncUnsafeCell::new(None), |
diff --git a/embassy-executor/src/raw/run_queue.rs b/embassy-executor/src/raw/run_queue.rs index 97060f4b9..e8a046a48 100644 --- a/embassy-executor/src/raw/run_queue.rs +++ b/embassy-executor/src/raw/run_queue.rs | |||
| @@ -108,11 +108,9 @@ impl RunQueue { | |||
| 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 = "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 | // SAFETY: `deadline` can only be set through the `Deadline` interface, which | 111 | let mut sorted = SortedList::<TaskHeader>::new_with_cmp(|lhs, rhs| { |
| 112 | // only allows access to this value while the given task is being polled. | 112 | lhs.deadline.instant_ticks().cmp(&rhs.deadline.instant_ticks()) |
| 113 | // This acts as mutual exclusion for access. | 113 | }); |
| 114 | let mut sorted = | ||
| 115 | SortedList::<TaskHeader>::new_with_cmp(|lhs, rhs| unsafe { lhs.deadline.get().cmp(&rhs.deadline.get()) }); | ||
| 116 | 114 | ||
| 117 | loop { | 115 | loop { |
| 118 | // For each loop, grab any newly pended items | 116 | // For each loop, grab any newly pended items |
