aboutsummaryrefslogtreecommitdiff
path: root/embassy-time-queue-driver
diff options
context:
space:
mode:
authorDániel Buga <[email protected]>2024-12-09 08:43:57 +0100
committerDániel Buga <[email protected]>2024-12-13 21:20:57 +0100
commitec96395d084d5edc8be25ddaea8547e2ebd447a6 (patch)
treeb1edf825c8d67013df3cec1283376a7558951a3f /embassy-time-queue-driver
parentd45ea43892198484b5f6dcea4c351dc11d226cc4 (diff)
Prevent task from respawning while in the timer queue
Diffstat (limited to 'embassy-time-queue-driver')
-rw-r--r--embassy-time-queue-driver/src/lib.rs14
-rw-r--r--embassy-time-queue-driver/src/queue_integrated.rs20
2 files changed, 29 insertions, 5 deletions
diff --git a/embassy-time-queue-driver/src/lib.rs b/embassy-time-queue-driver/src/lib.rs
index 0c78921ed..2d5fd449a 100644
--- a/embassy-time-queue-driver/src/lib.rs
+++ b/embassy-time-queue-driver/src/lib.rs
@@ -73,6 +73,20 @@ extern "Rust" {
73 73
74/// Schedule the given waker to be woken at `at`. 74/// Schedule the given waker to be woken at `at`.
75pub fn schedule_wake(at: u64, waker: &Waker) { 75pub fn schedule_wake(at: u64, waker: &Waker) {
76 #[cfg(feature = "integrated-timers")]
77 {
78 use embassy_executor::raw::task_from_waker;
79 use embassy_executor::raw::timer_queue::TimerEnqueueOperation;
80 // The very first thing we must do, before we even access the timer queue, is to
81 // mark the task a TIMER_QUEUED. This ensures that the task that is being scheduled
82 // can not be respawn while we are accessing the timer queue.
83 let task = task_from_waker(waker);
84 if unsafe { task.timer_enqueue() } == TimerEnqueueOperation::Ignore {
85 // We are not allowed to enqueue the task in the timer queue. This is because the
86 // task is not spawned, and so it makes no sense to schedule it.
87 return;
88 }
89 }
76 unsafe { _embassy_time_schedule_wake(at, waker) } 90 unsafe { _embassy_time_schedule_wake(at, waker) }
77} 91}
78 92
diff --git a/embassy-time-queue-driver/src/queue_integrated.rs b/embassy-time-queue-driver/src/queue_integrated.rs
index cb0f79356..b905c00c3 100644
--- a/embassy-time-queue-driver/src/queue_integrated.rs
+++ b/embassy-time-queue-driver/src/queue_integrated.rs
@@ -24,16 +24,21 @@ impl TimerQueue {
24 if item.next.get().is_none() { 24 if item.next.get().is_none() {
25 // If not in the queue, add it and update. 25 // If not in the queue, add it and update.
26 let prev = self.head.replace(Some(p)); 26 let prev = self.head.replace(Some(p));
27 item.next.set(prev); 27 item.next.set(if prev.is_none() {
28 Some(unsafe { TaskRef::dangling() })
29 } else {
30 prev
31 });
32 item.expires_at.set(at);
33 true
28 } else if at <= item.expires_at.get() { 34 } else if at <= item.expires_at.get() {
29 // If expiration is sooner than previously set, update. 35 // If expiration is sooner than previously set, update.
36 item.expires_at.set(at);
37 true
30 } else { 38 } else {
31 // Task does not need to be updated. 39 // Task does not need to be updated.
32 return false; 40 false
33 } 41 }
34
35 item.expires_at.set(at);
36 true
37 } 42 }
38 43
39 /// Dequeues expired timers and returns the next alarm time. 44 /// Dequeues expired timers and returns the next alarm time.
@@ -64,6 +69,10 @@ impl TimerQueue {
64 fn retain(&self, mut f: impl FnMut(TaskRef) -> bool) { 69 fn retain(&self, mut f: impl FnMut(TaskRef) -> bool) {
65 let mut prev = &self.head; 70 let mut prev = &self.head;
66 while let Some(p) = prev.get() { 71 while let Some(p) = prev.get() {
72 if unsafe { p == TaskRef::dangling() } {
73 // prev was the last item, stop
74 break;
75 }
67 let item = p.timer_queue_item(); 76 let item = p.timer_queue_item();
68 if f(p) { 77 if f(p) {
69 // Skip to next 78 // Skip to next
@@ -72,6 +81,7 @@ impl TimerQueue {
72 // Remove it 81 // Remove it
73 prev.set(item.next.get()); 82 prev.set(item.next.get());
74 item.next.set(None); 83 item.next.set(None);
84 unsafe { p.timer_dequeue() };
75 } 85 }
76 } 86 }
77 } 87 }