aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src
diff options
context:
space:
mode:
authorGrant Miller <[email protected]>2023-04-02 14:11:31 -0500
committerGrant Miller <[email protected]>2023-04-05 13:23:12 -0500
commit8290236ed64435453a9c028c95246a86371bd4ce (patch)
treed52e6d3f3f742cfb620432f715a8786a56e97a78 /embassy-executor/src
parenteed2b123253380d67f76bf1d0272688e8053bc9a (diff)
executor: Replace unsound critical sections with atomics
Diffstat (limited to 'embassy-executor/src')
-rw-r--r--embassy-executor/src/raw/mod.rs28
-rw-r--r--embassy-executor/src/raw/run_queue.rs18
2 files changed, 25 insertions, 21 deletions
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index f6c66da5a..bd0cff26b 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -22,7 +22,6 @@ use core::ptr::NonNull;
22use core::task::{Context, Poll}; 22use core::task::{Context, Poll};
23 23
24use atomic_polyfill::{AtomicU32, Ordering}; 24use atomic_polyfill::{AtomicU32, Ordering};
25use critical_section::CriticalSection;
26#[cfg(feature = "integrated-timers")] 25#[cfg(feature = "integrated-timers")]
27use embassy_time::driver::{self, AlarmHandle}; 26use embassy_time::driver::{self, AlarmHandle};
28#[cfg(feature = "integrated-timers")] 27#[cfg(feature = "integrated-timers")]
@@ -373,11 +372,11 @@ impl SyncExecutor {
373 /// - `task` must be set up to run in this executor. 372 /// - `task` must be set up to run in this executor.
374 /// - `task` must NOT be already enqueued (in this executor or another one). 373 /// - `task` must NOT be already enqueued (in this executor or another one).
375 #[inline(always)] 374 #[inline(always)]
376 unsafe fn enqueue(&self, cs: CriticalSection, task: TaskRef) { 375 unsafe fn enqueue(&self, task: TaskRef) {
377 #[cfg(feature = "rtos-trace")] 376 #[cfg(feature = "rtos-trace")]
378 trace::task_ready_begin(task.as_ptr() as u32); 377 trace::task_ready_begin(task.as_ptr() as u32);
379 378
380 if self.run_queue.enqueue(cs, task) { 379 if self.run_queue.enqueue(task) {
381 self.pender.pend(); 380 self.pender.pend();
382 } 381 }
383 } 382 }
@@ -394,9 +393,7 @@ impl SyncExecutor {
394 #[cfg(feature = "rtos-trace")] 393 #[cfg(feature = "rtos-trace")]
395 trace::task_new(task.as_ptr() as u32); 394 trace::task_new(task.as_ptr() as u32);
396 395
397 critical_section::with(|cs| { 396 self.enqueue(task);
398 self.enqueue(cs, task);
399 })
400 } 397 }
401 398
402 /// # Safety 399 /// # Safety
@@ -552,24 +549,25 @@ impl Executor {
552/// 549///
553/// You can obtain a `TaskRef` from a `Waker` using [`task_from_waker`]. 550/// You can obtain a `TaskRef` from a `Waker` using [`task_from_waker`].
554pub fn wake_task(task: TaskRef) { 551pub fn wake_task(task: TaskRef) {
555 critical_section::with(|cs| { 552 let header = task.header();
556 let header = task.header();
557 let state = header.state.load(Ordering::Relaxed);
558 553
554 let res = header.state.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| {
559 // If already scheduled, or if not started, 555 // If already scheduled, or if not started,
560 if (state & STATE_RUN_QUEUED != 0) || (state & STATE_SPAWNED == 0) { 556 if (state & STATE_RUN_QUEUED != 0) || (state & STATE_SPAWNED == 0) {
561 return; 557 None
558 } else {
559 // Mark it as scheduled
560 Some(state | STATE_RUN_QUEUED)
562 } 561 }
562 });
563 563
564 // Mark it as scheduled 564 if res.is_ok() {
565 header.state.store(state | STATE_RUN_QUEUED, Ordering::Relaxed);
566
567 // We have just marked the task as scheduled, so enqueue it. 565 // We have just marked the task as scheduled, so enqueue it.
568 unsafe { 566 unsafe {
569 let executor = header.executor.get().unwrap_unchecked(); 567 let executor = header.executor.get().unwrap_unchecked();
570 executor.enqueue(cs, task); 568 executor.enqueue(task);
571 } 569 }
572 }) 570 }
573} 571}
574 572
575#[cfg(feature = "integrated-timers")] 573#[cfg(feature = "integrated-timers")]
diff --git a/embassy-executor/src/raw/run_queue.rs b/embassy-executor/src/raw/run_queue.rs
index 362157535..a88174a0c 100644
--- a/embassy-executor/src/raw/run_queue.rs
+++ b/embassy-executor/src/raw/run_queue.rs
@@ -2,7 +2,6 @@ use core::ptr;
2use core::ptr::NonNull; 2use core::ptr::NonNull;
3 3
4use atomic_polyfill::{AtomicPtr, Ordering}; 4use atomic_polyfill::{AtomicPtr, Ordering};
5use critical_section::CriticalSection;
6 5
7use super::{TaskHeader, TaskRef}; 6use super::{TaskHeader, TaskRef};
8 7
@@ -46,11 +45,18 @@ impl RunQueue {
46 /// 45 ///
47 /// `item` must NOT be already enqueued in any queue. 46 /// `item` must NOT be already enqueued in any queue.
48 #[inline(always)] 47 #[inline(always)]
49 pub(crate) unsafe fn enqueue(&self, _cs: CriticalSection, task: TaskRef) -> bool { 48 pub(crate) unsafe fn enqueue(&self, task: TaskRef) -> bool {
50 let prev = self.head.load(Ordering::Relaxed); 49 let mut was_empty = false;
51 task.header().run_queue_item.next.store(prev, Ordering::Relaxed); 50
52 self.head.store(task.as_ptr() as _, Ordering::Relaxed); 51 self.head
53 prev.is_null() 52 .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |prev| {
53 was_empty = prev.is_null();
54 task.header().run_queue_item.next.store(prev, Ordering::Relaxed);
55 Some(task.as_ptr() as *mut _)
56 })
57 .ok();
58
59 was_empty
54 } 60 }
55 61
56 /// Empty the queue, then call `on_task` for each task that was in the queue. 62 /// Empty the queue, then call `on_task` for each task that was in the queue.