aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src
diff options
context:
space:
mode:
authorJames Munns <[email protected]>2025-04-01 18:35:41 +0200
committerDario Nieuwenhuis <[email protected]>2025-09-11 14:45:06 +0200
commit8c70aafd4be63ff7af895f116444fb81438ae6e0 (patch)
tree9d34e4eebf29b9a6e32b477691721ff30b737c88 /embassy-executor/src
parent1f50e4d496458dbc7fccd9d028217ebfa7735471 (diff)
Make some things more consistent
Diffstat (limited to 'embassy-executor/src')
-rw-r--r--embassy-executor/src/raw/mod.rs53
-rw-r--r--embassy-executor/src/raw/run_queue_drs_atomics.rs31
2 files changed, 31 insertions, 53 deletions
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;
40use core::mem; 40use core::mem;
41use core::pin::Pin; 41use core::pin::Pin;
42use core::ptr::NonNull; 42use core::ptr::NonNull;
43#[cfg(feature = "drs-scheduler")]
44use core::ptr::addr_of_mut; 43use core::ptr::addr_of_mut;
45#[cfg(not(feature = "arch-avr"))] 44#[cfg(not(feature = "arch-avr"))]
46use core::sync::atomic::AtomicPtr; 45use core::sync::atomic::AtomicPtr;
@@ -51,9 +50,7 @@ use embassy_executor_timer_queue::TimerQueueItem;
51#[cfg(feature = "arch-avr")] 50#[cfg(feature = "arch-avr")]
52use portable_atomic::AtomicPtr; 51use portable_atomic::AtomicPtr;
53 52
54use self::run_queue::RunQueue; 53use self::run_queue::{RunQueue, RunQueueItem};
55#[cfg(not(feature = "drs-scheduler"))]
56use self::run_queue::RunQueueItem;
57use self::state::State; 54use self::state::State;
58use self::util::{SyncUnsafeCell, UninitCell}; 55use self::util::{SyncUnsafeCell, UninitCell};
59pub use self::waker::task_from_waker; 56pub 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")]
69use cordyceps::{stack, Linked};
70
71#[cfg(feature = "drs-scheduler")]
72pub use run_queue::Deadline; 66pub 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))]
114pub(crate) struct TaskHeader { 107pub(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")]
152unsafe 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)]
172pub struct TaskRef { 130pub 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};
2use cordyceps::{SortedList, TransferStack}; 2use cordyceps::{SortedList, TransferStack};
3use core::future::{Future, poll_fn}; 3use core::future::{Future, poll_fn};
4use core::task::Poll; 4use core::task::Poll;
5use core::ptr::{addr_of_mut, NonNull};
6use cordyceps::sorted_list::Links;
7use cordyceps::Linked;
8
9pub(crate) type RunQueueItem = Links<TaskHeader>;
10
11unsafe 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