diff options
Diffstat (limited to 'embassy-executor/src/raw')
| -rw-r--r-- | embassy-executor/src/raw/deadline.rs | 2 | ||||
| -rw-r--r-- | embassy-executor/src/raw/mod.rs | 11 | ||||
| -rw-r--r-- | embassy-executor/src/raw/run_queue_atomics.rs | 19 |
3 files changed, 25 insertions, 7 deletions
diff --git a/embassy-executor/src/raw/deadline.rs b/embassy-executor/src/raw/deadline.rs index 3f60936cc..c8cc94c52 100644 --- a/embassy-executor/src/raw/deadline.rs +++ b/embassy-executor/src/raw/deadline.rs | |||
| @@ -2,6 +2,8 @@ use core::future::{poll_fn, Future}; | |||
| 2 | use core::task::Poll; | 2 | use core::task::Poll; |
| 3 | 3 | ||
| 4 | /// A type for interacting with the deadline of the current task | 4 | /// A type for interacting with the deadline of the current task |
| 5 | /// | ||
| 6 | /// Requires the `drs-scheduler` feature | ||
| 5 | pub struct Deadline { | 7 | pub struct Deadline { |
| 6 | /// Deadline value in ticks, same time base and ticks as `embassy-time` | 8 | /// Deadline value in ticks, same time base and ticks as `embassy-time` |
| 7 | pub instant_ticks: u64, | 9 | pub instant_ticks: u64, |
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 0dd247d30..f4fbe1bfc 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs | |||
| @@ -101,14 +101,14 @@ extern "Rust" fn __embassy_time_queue_item_from_waker(waker: &Waker) -> &'static | |||
| 101 | /// - 5: Task is dequeued. The task's future is not polled, because exiting the task replaces its `poll_fn`. | 101 | /// - 5: Task is dequeued. The task's future is not polled, because exiting the task replaces its `poll_fn`. |
| 102 | /// - 6: A task is waken when it is not spawned - `wake_task -> State::run_enqueue` | 102 | /// - 6: A task is waken when it is not spawned - `wake_task -> State::run_enqueue` |
| 103 | pub(crate) struct TaskHeader { | 103 | pub(crate) struct TaskHeader { |
| 104 | pub(crate) state: State, | ||
| 104 | pub(crate) run_queue_item: RunQueueItem, | 105 | pub(crate) run_queue_item: RunQueueItem, |
| 105 | 106 | ||
| 106 | #[cfg(feature = "drs-scheduler")] | ||
| 107 | /// Deadline Rank Scheduler Deadline. This field should not be accessed outside the context of | 107 | /// Deadline Rank Scheduler Deadline. This field should not be accessed outside the context of |
| 108 | /// the task itself as it being polled by the executor. | 108 | /// the task itself as it being polled by the executor. |
| 109 | #[cfg(feature = "drs-scheduler")] | ||
| 109 | pub(crate) deadline: SyncUnsafeCell<u64>, | 110 | pub(crate) deadline: SyncUnsafeCell<u64>, |
| 110 | 111 | ||
| 111 | pub(crate) state: State, | ||
| 112 | pub(crate) executor: AtomicPtr<SyncExecutor>, | 112 | pub(crate) executor: AtomicPtr<SyncExecutor>, |
| 113 | poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>, | 113 | poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>, |
| 114 | 114 | ||
| @@ -211,10 +211,12 @@ impl<F: Future + 'static> TaskStorage<F> { | |||
| 211 | pub const fn new() -> Self { | 211 | pub const fn new() -> Self { |
| 212 | Self { | 212 | Self { |
| 213 | raw: TaskHeader { | 213 | raw: TaskHeader { |
| 214 | state: State::new(), | ||
| 214 | run_queue_item: RunQueueItem::new(), | 215 | run_queue_item: RunQueueItem::new(), |
| 216 | // NOTE: The deadline is set to zero to allow the initializer to reside in `.bss`. This | ||
| 217 | // will be lazily initalized in `initialize_impl` | ||
| 215 | #[cfg(feature = "drs-scheduler")] | 218 | #[cfg(feature = "drs-scheduler")] |
| 216 | deadline: SyncUnsafeCell::new(0u64), | 219 | deadline: SyncUnsafeCell::new(0u64), |
| 217 | state: State::new(), | ||
| 218 | executor: AtomicPtr::new(core::ptr::null_mut()), | 220 | executor: AtomicPtr::new(core::ptr::null_mut()), |
| 219 | // Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss` | 221 | // Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss` |
| 220 | poll_fn: SyncUnsafeCell::new(None), | 222 | poll_fn: SyncUnsafeCell::new(None), |
| @@ -311,7 +313,8 @@ impl<F: Future + 'static> AvailableTask<F> { | |||
| 311 | self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll)); | 313 | self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll)); |
| 312 | self.task.future.write_in_place(future); | 314 | self.task.future.write_in_place(future); |
| 313 | 315 | ||
| 314 | // TODO(AJM): Some other way of setting this? Just a placeholder | 316 | // By default, deadlines are set to the maximum value, so that any task WITH |
| 317 | // a set deadline will ALWAYS be scheduled BEFORE a task WITHOUT a set deadline | ||
| 315 | #[cfg(feature = "drs-scheduler")] | 318 | #[cfg(feature = "drs-scheduler")] |
| 316 | self.task.raw.deadline.set(u64::MAX); | 319 | self.task.raw.deadline.set(u64::MAX); |
| 317 | 320 | ||
diff --git a/embassy-executor/src/raw/run_queue_atomics.rs b/embassy-executor/src/raw/run_queue_atomics.rs index bc5d38250..3715fc658 100644 --- a/embassy-executor/src/raw/run_queue_atomics.rs +++ b/embassy-executor/src/raw/run_queue_atomics.rs | |||
| @@ -66,6 +66,8 @@ impl RunQueue { | |||
| 66 | self.stack.push_was_empty(task) | 66 | self.stack.push_was_empty(task) |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | /// # Standard atomic runqueue | ||
| 70 | /// | ||
| 69 | /// Empty the queue, then call `on_task` for each task that was in the queue. | 71 | /// Empty the queue, then call `on_task` for each task that was in the queue. |
| 70 | /// NOTE: It is OK for `on_task` to enqueue more tasks. In this case they're left in the queue | 72 | /// NOTE: It is OK for `on_task` to enqueue more tasks. In this case they're left in the queue |
| 71 | /// and will be processed by the *next* call to `dequeue_all`, *not* the current one. | 73 | /// and will be processed by the *next* call to `dequeue_all`, *not* the current one. |
| @@ -78,9 +80,20 @@ impl RunQueue { | |||
| 78 | } | 80 | } |
| 79 | } | 81 | } |
| 80 | 82 | ||
| 81 | /// Empty the queue, then call `on_task` for each task that was in the queue. | 83 | /// # Deadline Ranked Sorted Scheduler |
| 82 | /// NOTE: It is OK for `on_task` to enqueue more tasks. In this case they're left in the queue | 84 | /// |
| 83 | /// and will be processed by the *next* call to `dequeue_all`, *not* the current one. | 85 | /// This algorithm will loop until all enqueued tasks are processed. |
| 86 | /// | ||
| 87 | /// Before polling a task, all currently enqueued tasks will be popped from the | ||
| 88 | /// runqueue, and will be added to the working `sorted` list, a linked-list that | ||
| 89 | /// sorts tasks by their deadline, with nearest deadline items in the front, and | ||
| 90 | /// furthest deadline items in the back. | ||
| 91 | /// | ||
| 92 | /// After popping and sorting all pending tasks, the SOONEST task will be popped | ||
| 93 | /// from the front of the queue, and polled by calling `on_task` on it. | ||
| 94 | /// | ||
| 95 | /// This process will repeat until the local `sorted` queue AND the global | ||
| 96 | /// runqueue are both empty, at which point this function will return. | ||
| 84 | #[cfg(feature = "drs-scheduler")] | 97 | #[cfg(feature = "drs-scheduler")] |
| 85 | pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) { | 98 | pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) { |
| 86 | // SAFETY: `deadline` can only be set through the `Deadline` interface, which | 99 | // SAFETY: `deadline` can only be set through the `Deadline` interface, which |
