diff options
| author | James Munns <[email protected]> | 2025-04-01 18:35:41 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2025-09-11 14:45:06 +0200 |
| commit | 8c70aafd4be63ff7af895f116444fb81438ae6e0 (patch) | |
| tree | 9d34e4eebf29b9a6e32b477691721ff30b737c88 | |
| parent | 1f50e4d496458dbc7fccd9d028217ebfa7735471 (diff) | |
Make some things more consistent
| -rw-r--r-- | embassy-executor/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-executor/src/raw/mod.rs | 53 | ||||
| -rw-r--r-- | embassy-executor/src/raw/run_queue_drs_atomics.rs | 31 |
3 files changed, 34 insertions, 54 deletions
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index db664a819..80b5867c9 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml | |||
| @@ -77,9 +77,11 @@ js-sys = { version = "0.3", optional = true } | |||
| 77 | avr-device = { version = "0.7.0", optional = true } | 77 | avr-device = { version = "0.7.0", optional = true } |
| 78 | 78 | ||
| 79 | [dependencies.cordyceps] | 79 | [dependencies.cordyceps] |
| 80 | # note: targeting v0.3.3, to be released when | ||
| 81 | # https://github.com/hawkw/mycelium/pull/520 is merged | ||
| 80 | version = "0.3" | 82 | version = "0.3" |
| 81 | git = "https://github.com/hawkw/mycelium" | 83 | git = "https://github.com/hawkw/mycelium" |
| 82 | rev = "aaad19480d175bfc290f1d4dc2d435c6eb3d9fc5" | 84 | rev = "9649db0525b9972b95937d83d52d3f51cc486281" |
| 83 | optional = true | 85 | optional = true |
| 84 | 86 | ||
| 85 | [dev-dependencies] | 87 | [dev-dependencies] |
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 9b8a4ea8a..2e5941ef7 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs | |||
| @@ -40,7 +40,6 @@ use core::marker::PhantomData; | |||
| 40 | use core::mem; | 40 | use core::mem; |
| 41 | use core::pin::Pin; | 41 | use core::pin::Pin; |
| 42 | use core::ptr::NonNull; | 42 | use core::ptr::NonNull; |
| 43 | #[cfg(feature = "drs-scheduler")] | ||
| 44 | use core::ptr::addr_of_mut; | 43 | use core::ptr::addr_of_mut; |
| 45 | #[cfg(not(feature = "arch-avr"))] | 44 | #[cfg(not(feature = "arch-avr"))] |
| 46 | use core::sync::atomic::AtomicPtr; | 45 | use core::sync::atomic::AtomicPtr; |
| @@ -51,9 +50,7 @@ use embassy_executor_timer_queue::TimerQueueItem; | |||
| 51 | #[cfg(feature = "arch-avr")] | 50 | #[cfg(feature = "arch-avr")] |
| 52 | use portable_atomic::AtomicPtr; | 51 | use portable_atomic::AtomicPtr; |
| 53 | 52 | ||
| 54 | use self::run_queue::RunQueue; | 53 | use self::run_queue::{RunQueue, RunQueueItem}; |
| 55 | #[cfg(not(feature = "drs-scheduler"))] | ||
| 56 | use self::run_queue::RunQueueItem; | ||
| 57 | use self::state::State; | 54 | use self::state::State; |
| 58 | use self::util::{SyncUnsafeCell, UninitCell}; | 55 | use self::util::{SyncUnsafeCell, UninitCell}; |
| 59 | pub use self::waker::task_from_waker; | 56 | pub use self::waker::task_from_waker; |
| @@ -66,9 +63,6 @@ extern "Rust" fn __embassy_time_queue_item_from_waker(waker: &Waker) -> &'static | |||
| 66 | } | 63 | } |
| 67 | 64 | ||
| 68 | #[cfg(feature = "drs-scheduler")] | 65 | #[cfg(feature = "drs-scheduler")] |
| 69 | use cordyceps::{stack, Linked}; | ||
| 70 | |||
| 71 | #[cfg(feature = "drs-scheduler")] | ||
| 72 | pub use run_queue::Deadline; | 66 | pub use run_queue::Deadline; |
| 73 | 67 | ||
| 74 | /// Raw task header for use in task pointers. | 68 | /// Raw task header for use in task pointers. |
| @@ -110,31 +104,14 @@ pub use run_queue::Deadline; | |||
| 110 | /// - 4: A run-queued task exits - `TaskStorage::poll -> Poll::Ready` | 104 | /// - 4: A run-queued task exits - `TaskStorage::poll -> Poll::Ready` |
| 111 | /// - 5: Task is dequeued. The task's future is not polled, because exiting the task replaces its `poll_fn`. | 105 | /// - 5: Task is dequeued. The task's future is not polled, because exiting the task replaces its `poll_fn`. |
| 112 | /// - 6: A task is waken when it is not spawned - `wake_task -> State::run_enqueue` | 106 | /// - 6: A task is waken when it is not spawned - `wake_task -> State::run_enqueue` |
| 113 | #[cfg_attr(feature = "drs-scheduler", repr(C))] | ||
| 114 | pub(crate) struct TaskHeader { | 107 | pub(crate) struct TaskHeader { |
| 115 | // TODO(AJM): Make a decision whether we want to support the spicier "pointer recast"/"type punning" | 108 | pub(crate) run_queue_item: RunQueueItem, |
| 116 | // method of implementing the `cordyceps::Linked` trait or not. | ||
| 117 | // | ||
| 118 | // Currently, I do the safer version with `addr_of_mut!`, which doesn't REQUIRE that the first | ||
| 119 | // element is the `links` field, at the potential cost of a little extra pointer math. | ||
| 120 | // | ||
| 121 | // The optimizer *might* (total guess) notice that we are always doing an offset of zero in the | ||
| 122 | // call to `addr_of_mut` in the `impl Linked for TaskHeader` below, and get the best of both worlds, | ||
| 123 | // but right now this is maybe a little over cautious. | ||
| 124 | // | ||
| 125 | // See https://docs.rs/cordyceps/latest/cordyceps/trait.Linked.html#implementing-linkedlinks for | ||
| 126 | // more context on the choices here. | ||
| 127 | #[cfg(feature = "drs-scheduler")] | ||
| 128 | pub(crate) links: stack::Links<TaskHeader>, | ||
| 129 | 109 | ||
| 130 | #[cfg(feature = "drs-scheduler")] | 110 | #[cfg(feature = "drs-scheduler")] |
| 111 | /// Deadline Rank Scheduler Deadline. This field should not be accessed outside the context of | ||
| 112 | /// the task itself as it being polled by the executor. | ||
| 131 | pub(crate) deadline: SyncUnsafeCell<u64>, | 113 | pub(crate) deadline: SyncUnsafeCell<u64>, |
| 132 | 114 | ||
| 133 | // TODO(AJM): We could potentially replace RunQueueItem for other runqueue impls, though | ||
| 134 | // right now cordyceps doesn't work on non-atomic systems | ||
| 135 | #[cfg(not(feature = "drs-scheduler"))] | ||
| 136 | pub(crate) run_queue_item: RunQueueItem, | ||
| 137 | |||
| 138 | pub(crate) state: State, | 115 | pub(crate) state: State, |
| 139 | pub(crate) executor: AtomicPtr<SyncExecutor>, | 116 | pub(crate) executor: AtomicPtr<SyncExecutor>, |
| 140 | poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>, | 117 | poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>, |
| @@ -148,25 +125,6 @@ pub(crate) struct TaskHeader { | |||
| 148 | all_tasks_next: AtomicPtr<TaskHeader>, | 125 | all_tasks_next: AtomicPtr<TaskHeader>, |
| 149 | } | 126 | } |
| 150 | 127 | ||
| 151 | #[cfg(feature = "drs-scheduler")] | ||
| 152 | unsafe impl Linked<stack::Links<TaskHeader>> for TaskHeader { | ||
| 153 | type Handle = TaskRef; | ||
| 154 | |||
| 155 | fn into_ptr(r: Self::Handle) -> NonNull<Self> { | ||
| 156 | r.ptr.cast() | ||
| 157 | } | ||
| 158 | |||
| 159 | unsafe fn from_ptr(ptr: NonNull<Self>) -> Self::Handle { | ||
| 160 | let ptr: NonNull<TaskHeader> = ptr; | ||
| 161 | TaskRef { ptr } | ||
| 162 | } | ||
| 163 | |||
| 164 | unsafe fn links(ptr: NonNull<Self>) -> NonNull<stack::Links<TaskHeader>> { | ||
| 165 | let ptr: *mut TaskHeader = ptr.as_ptr(); | ||
| 166 | NonNull::new_unchecked(addr_of_mut!((*ptr).links)) | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | /// This is essentially a `&'static TaskStorage<F>` where the type of the future has been erased. | 128 | /// This is essentially a `&'static TaskStorage<F>` where the type of the future has been erased. |
| 171 | #[derive(Debug, Clone, Copy, PartialEq)] | 129 | #[derive(Debug, Clone, Copy, PartialEq)] |
| 172 | pub struct TaskRef { | 130 | pub struct TaskRef { |
| @@ -257,11 +215,8 @@ impl<F: Future + 'static> TaskStorage<F> { | |||
| 257 | pub const fn new() -> Self { | 215 | pub const fn new() -> Self { |
| 258 | Self { | 216 | Self { |
| 259 | raw: TaskHeader { | 217 | raw: TaskHeader { |
| 260 | #[cfg(not(feature = "drs-scheduler"))] | ||
| 261 | run_queue_item: RunQueueItem::new(), | 218 | run_queue_item: RunQueueItem::new(), |
| 262 | #[cfg(feature = "drs-scheduler")] | 219 | #[cfg(feature = "drs-scheduler")] |
| 263 | links: stack::Links::new(), | ||
| 264 | #[cfg(feature = "drs-scheduler")] | ||
| 265 | deadline: SyncUnsafeCell::new(0u64), | 220 | deadline: SyncUnsafeCell::new(0u64), |
| 266 | state: State::new(), | 221 | state: State::new(), |
| 267 | executor: AtomicPtr::new(core::ptr::null_mut()), | 222 | executor: AtomicPtr::new(core::ptr::null_mut()), |
diff --git a/embassy-executor/src/raw/run_queue_drs_atomics.rs b/embassy-executor/src/raw/run_queue_drs_atomics.rs index 69b7b3bf0..047265954 100644 --- a/embassy-executor/src/raw/run_queue_drs_atomics.rs +++ b/embassy-executor/src/raw/run_queue_drs_atomics.rs | |||
| @@ -2,6 +2,29 @@ use super::{TaskHeader, TaskRef}; | |||
| 2 | use cordyceps::{SortedList, TransferStack}; | 2 | use cordyceps::{SortedList, TransferStack}; |
| 3 | use core::future::{Future, poll_fn}; | 3 | use core::future::{Future, poll_fn}; |
| 4 | use core::task::Poll; | 4 | use core::task::Poll; |
| 5 | use core::ptr::{addr_of_mut, NonNull}; | ||
| 6 | use cordyceps::sorted_list::Links; | ||
| 7 | use cordyceps::Linked; | ||
| 8 | |||
| 9 | pub(crate) type RunQueueItem = Links<TaskHeader>; | ||
| 10 | |||
| 11 | unsafe impl Linked<Links<TaskHeader>> for super::TaskHeader { | ||
| 12 | type Handle = TaskRef; | ||
| 13 | |||
| 14 | fn into_ptr(r: Self::Handle) -> NonNull<Self> { | ||
| 15 | r.ptr.cast() | ||
| 16 | } | ||
| 17 | |||
| 18 | unsafe fn from_ptr(ptr: NonNull<Self>) -> Self::Handle { | ||
| 19 | let ptr: NonNull<TaskHeader> = ptr; | ||
| 20 | TaskRef { ptr } | ||
| 21 | } | ||
| 22 | |||
| 23 | unsafe fn links(ptr: NonNull<Self>) -> NonNull<Links<TaskHeader>> { | ||
| 24 | let ptr: *mut TaskHeader = ptr.as_ptr(); | ||
| 25 | NonNull::new_unchecked(addr_of_mut!((*ptr).run_queue_item)) | ||
| 26 | } | ||
| 27 | } | ||
| 5 | 28 | ||
| 6 | /// Atomic task queue using a very, very simple lock-free linked-list queue: | 29 | /// Atomic task queue using a very, very simple lock-free linked-list queue: |
| 7 | /// | 30 | /// |
| @@ -39,10 +62,10 @@ impl RunQueue { | |||
| 39 | /// NOTE: It is OK for `on_task` to enqueue more tasks. In this case they're left in the queue | 62 | /// NOTE: It is OK for `on_task` to enqueue more tasks. In this case they're left in the queue |
| 40 | /// and will be processed by the *next* call to `dequeue_all`, *not* the current one. | 63 | /// and will be processed by the *next* call to `dequeue_all`, *not* the current one. |
| 41 | pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) { | 64 | pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) { |
| 42 | let mut sorted = SortedList::<TaskHeader>::new(|lhs, rhs| unsafe { | 65 | // SAFETY: `deadline` can only be set through the `Deadline` interface, which |
| 43 | // TODO: Do we need any kind of access control here? Not if we say that | 66 | // only allows access to this value while the given task is being polled. |
| 44 | // tasks can only set their own priority, which they can't do if we're in | 67 | // This acts as mutual exclusion for access. |
| 45 | // the scheduler | 68 | let mut sorted = SortedList::<TaskHeader>::new_custom(|lhs, rhs| unsafe { |
| 46 | lhs.deadline.get().cmp(&rhs.deadline.get()) | 69 | lhs.deadline.get().cmp(&rhs.deadline.get()) |
| 47 | }); | 70 | }); |
| 48 | 71 | ||
