diff options
Diffstat (limited to 'embassy-executor')
| -rw-r--r-- | embassy-executor/src/raw/mod.rs | 21 | ||||
| -rw-r--r-- | embassy-executor/src/raw/timer_queue.rs | 5 |
2 files changed, 18 insertions, 8 deletions
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index b825fa6c2..7da14468d 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs | |||
| @@ -94,13 +94,14 @@ impl TaskRef { | |||
| 94 | &self.header().timer_queue_item | 94 | &self.header().timer_queue_item |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | /// Mark the task as timer-queued. Return whether it was newly queued (i.e. not queued before) | 97 | /// Mark the task as timer-queued. Return whether it should be actually enqueued |
| 98 | /// using `_embassy_time_schedule_wake`. | ||
| 98 | /// | 99 | /// |
| 99 | /// Entering this state prevents the task from being respawned while in a timer queue. | 100 | /// Entering this state prevents the task from being respawned while in a timer queue. |
| 100 | /// | 101 | /// |
| 101 | /// Safety: | 102 | /// Safety: |
| 102 | /// | 103 | /// |
| 103 | /// This functions should only be called by the timer queue implementation, before | 104 | /// This functions should only be called by the timer queue driver, before |
| 104 | /// enqueueing the timer item. | 105 | /// enqueueing the timer item. |
| 105 | pub unsafe fn timer_enqueue(&self) -> timer_queue::TimerEnqueueOperation { | 106 | pub unsafe fn timer_enqueue(&self) -> timer_queue::TimerEnqueueOperation { |
| 106 | self.header().state.timer_enqueue() | 107 | self.header().state.timer_enqueue() |
| @@ -193,16 +194,24 @@ impl<F: Future + 'static> TaskStorage<F> { | |||
| 193 | Poll::Ready(_) => { | 194 | Poll::Ready(_) => { |
| 194 | this.future.drop_in_place(); | 195 | this.future.drop_in_place(); |
| 195 | 196 | ||
| 196 | // Mark this task to be timer queued, to prevent re-queueing it. | 197 | // Mark this task to be timer queued. |
| 197 | this.raw.state.timer_enqueue(); | 198 | // We're splitting the enqueue in two parts, so that we can change task state |
| 199 | // to something that prevent re-queueing. | ||
| 200 | let op = this.raw.state.timer_enqueue(); | ||
| 198 | 201 | ||
| 199 | // Now mark the task as not spawned, so that | 202 | // Now mark the task as not spawned, so that |
| 200 | // - it can be spawned again once it has been removed from the timer queue | 203 | // - it can be spawned again once it has been removed from the timer queue |
| 201 | // - it can not be timer-queued again | 204 | // - it can not be timer-queued again |
| 205 | // We must do this before scheduling the wake, to prevent the task from being | ||
| 206 | // dequeued by the time driver while it's still SPAWNED. | ||
| 202 | this.raw.state.despawn(); | 207 | this.raw.state.despawn(); |
| 203 | 208 | ||
| 204 | // Schedule the task by hand in the past, so it runs immediately. | 209 | // Now let's finish enqueueing. While we shouldn't get an `Ignore` here, it's |
| 205 | unsafe { _embassy_time_schedule_wake(0, &waker) } | 210 | // better to be safe. |
| 211 | if op == timer_queue::TimerEnqueueOperation::Enqueue { | ||
| 212 | // Schedule the task in the past, so it gets dequeued ASAP. | ||
| 213 | unsafe { _embassy_time_schedule_wake(0, &waker) } | ||
| 214 | } | ||
| 206 | } | 215 | } |
| 207 | Poll::Pending => {} | 216 | Poll::Pending => {} |
| 208 | } | 217 | } |
diff --git a/embassy-executor/src/raw/timer_queue.rs b/embassy-executor/src/raw/timer_queue.rs index c36708401..cd9a73822 100644 --- a/embassy-executor/src/raw/timer_queue.rs +++ b/embassy-executor/src/raw/timer_queue.rs | |||
| @@ -30,9 +30,10 @@ impl TimerQueueItem { | |||
| 30 | /// The operation to perform after `timer_enqueue` is called. | 30 | /// The operation to perform after `timer_enqueue` is called. |
| 31 | #[derive(Debug, Copy, Clone, PartialEq)] | 31 | #[derive(Debug, Copy, Clone, PartialEq)] |
| 32 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 32 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 33 | #[must_use] | ||
| 33 | pub enum TimerEnqueueOperation { | 34 | pub enum TimerEnqueueOperation { |
| 34 | /// Enqueue the task. | 35 | /// Enqueue the task (or update its expiration time). |
| 35 | Enqueue, | 36 | Enqueue, |
| 36 | /// Update the task's expiration time. | 37 | /// The task must not be enqueued in the timer queue. |
| 37 | Ignore, | 38 | Ignore, |
| 38 | } | 39 | } |
