diff options
| author | Dániel Buga <[email protected]> | 2024-12-16 17:24:17 +0100 |
|---|---|---|
| committer | Dániel Buga <[email protected]> | 2024-12-16 17:29:07 +0100 |
| commit | b47a631abf0c200c3b29b8e4ec199421835a0525 (patch) | |
| tree | 4eacf2103588ac1b1df52f6fe233fa787715d78d /embassy-executor | |
| parent | b44ef5ccb40d6b778e623e6e68a234c2e0615d25 (diff) | |
Rely on atomic load-store on all targets
Diffstat (limited to 'embassy-executor')
| -rw-r--r-- | embassy-executor/src/raw/mod.rs | 72 | ||||
| -rw-r--r-- | embassy-executor/src/spawner.rs | 21 |
2 files changed, 25 insertions, 68 deletions
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 808a78389..5a476213b 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs | |||
| @@ -14,58 +14,7 @@ mod run_queue; | |||
| 14 | #[cfg_attr(all(cortex_m, target_has_atomic = "8"), path = "state_atomics_arm.rs")] | 14 | #[cfg_attr(all(cortex_m, target_has_atomic = "8"), path = "state_atomics_arm.rs")] |
| 15 | #[cfg_attr(all(not(cortex_m), target_has_atomic = "8"), path = "state_atomics.rs")] | 15 | #[cfg_attr(all(not(cortex_m), target_has_atomic = "8"), path = "state_atomics.rs")] |
| 16 | #[cfg_attr(not(target_has_atomic = "8"), path = "state_critical_section.rs")] | 16 | #[cfg_attr(not(target_has_atomic = "8"), path = "state_critical_section.rs")] |
| 17 | pub(crate) mod state; | 17 | mod state; |
| 18 | |||
| 19 | #[cfg(target_has_atomic = "ptr")] | ||
| 20 | mod owner { | ||
| 21 | use core::sync::atomic::{AtomicPtr, Ordering}; | ||
| 22 | |||
| 23 | use super::{state::Token, SyncExecutor}; | ||
| 24 | |||
| 25 | pub(crate) struct ExecutorRef(AtomicPtr<SyncExecutor>); | ||
| 26 | |||
| 27 | impl ExecutorRef { | ||
| 28 | pub const fn new() -> Self { | ||
| 29 | Self(AtomicPtr::new(core::ptr::null_mut())) | ||
| 30 | } | ||
| 31 | |||
| 32 | pub fn set(&self, executor: Option<&'static SyncExecutor>, _: Token) { | ||
| 33 | let ptr = executor.map(|e| e as *const SyncExecutor).unwrap_or(core::ptr::null()); | ||
| 34 | self.0.store(ptr.cast_mut(), Ordering::Release); | ||
| 35 | } | ||
| 36 | |||
| 37 | pub fn get(&self, _: Token) -> *const SyncExecutor { | ||
| 38 | self.0.load(Ordering::Acquire).cast_const() | ||
| 39 | } | ||
| 40 | } | ||
| 41 | } | ||
| 42 | #[cfg(not(target_has_atomic = "ptr"))] | ||
| 43 | mod owner { | ||
| 44 | use super::{state::Token, SyncExecutor}; | ||
| 45 | use core::cell::Cell; | ||
| 46 | |||
| 47 | use critical_section::Mutex; | ||
| 48 | |||
| 49 | pub(crate) struct ExecutorRef(Mutex<Cell<*const SyncExecutor>>); | ||
| 50 | |||
| 51 | unsafe impl Send for ExecutorRef {} | ||
| 52 | unsafe impl Sync for ExecutorRef {} | ||
| 53 | |||
| 54 | impl ExecutorRef { | ||
| 55 | pub const fn new() -> Self { | ||
| 56 | Self(Mutex::new(Cell::new(core::ptr::null()))) | ||
| 57 | } | ||
| 58 | |||
| 59 | pub fn set(&self, executor: Option<&'static SyncExecutor>, cs: Token) { | ||
| 60 | let ptr = executor.map(|e| e as *const SyncExecutor).unwrap_or(core::ptr::null()); | ||
| 61 | self.0.borrow(cs).set(ptr); | ||
| 62 | } | ||
| 63 | |||
| 64 | pub fn get(&self, cs: Token) -> *const SyncExecutor { | ||
| 65 | self.0.borrow(cs).get() | ||
| 66 | } | ||
| 67 | } | ||
| 68 | } | ||
| 69 | 18 | ||
| 70 | pub mod timer_queue; | 19 | pub mod timer_queue; |
| 71 | #[cfg(feature = "trace")] | 20 | #[cfg(feature = "trace")] |
| @@ -79,10 +28,9 @@ use core::marker::PhantomData; | |||
| 79 | use core::mem; | 28 | use core::mem; |
| 80 | use core::pin::Pin; | 29 | use core::pin::Pin; |
| 81 | use core::ptr::NonNull; | 30 | use core::ptr::NonNull; |
| 31 | use core::sync::atomic::{AtomicPtr, Ordering}; | ||
| 82 | use core::task::{Context, Poll}; | 32 | use core::task::{Context, Poll}; |
| 83 | 33 | ||
| 84 | use crate::raw::owner::ExecutorRef; | ||
| 85 | |||
| 86 | use self::run_queue::{RunQueue, RunQueueItem}; | 34 | use self::run_queue::{RunQueue, RunQueueItem}; |
| 87 | use self::state::State; | 35 | use self::state::State; |
| 88 | use self::util::{SyncUnsafeCell, UninitCell}; | 36 | use self::util::{SyncUnsafeCell, UninitCell}; |
| @@ -93,7 +41,7 @@ use super::SpawnToken; | |||
| 93 | pub(crate) struct TaskHeader { | 41 | pub(crate) struct TaskHeader { |
| 94 | pub(crate) state: State, | 42 | pub(crate) state: State, |
| 95 | pub(crate) run_queue_item: RunQueueItem, | 43 | pub(crate) run_queue_item: RunQueueItem, |
| 96 | pub(crate) executor: ExecutorRef, | 44 | pub(crate) executor: AtomicPtr<SyncExecutor>, |
| 97 | poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>, | 45 | poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>, |
| 98 | 46 | ||
| 99 | /// Integrated timer queue storage. This field should not be accessed outside of the timer queue. | 47 | /// Integrated timer queue storage. This field should not be accessed outside of the timer queue. |
| @@ -139,7 +87,7 @@ impl TaskRef { | |||
| 139 | 87 | ||
| 140 | /// Returns a reference to the executor that the task is currently running on. | 88 | /// Returns a reference to the executor that the task is currently running on. |
| 141 | pub unsafe fn executor(self) -> Option<&'static Executor> { | 89 | pub unsafe fn executor(self) -> Option<&'static Executor> { |
| 142 | let executor = state::locked(|token| self.header().executor.get(token)); | 90 | let executor = self.header().executor.load(Ordering::Relaxed); |
| 143 | executor.as_ref().map(|e| Executor::wrap(e)) | 91 | executor.as_ref().map(|e| Executor::wrap(e)) |
| 144 | } | 92 | } |
| 145 | 93 | ||
| @@ -207,7 +155,7 @@ impl<F: Future + 'static> TaskStorage<F> { | |||
| 207 | raw: TaskHeader { | 155 | raw: TaskHeader { |
| 208 | state: State::new(), | 156 | state: State::new(), |
| 209 | run_queue_item: RunQueueItem::new(), | 157 | run_queue_item: RunQueueItem::new(), |
| 210 | executor: ExecutorRef::new(), | 158 | executor: AtomicPtr::new(core::ptr::null_mut()), |
| 211 | // Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss` | 159 | // Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss` |
| 212 | poll_fn: SyncUnsafeCell::new(None), | 160 | poll_fn: SyncUnsafeCell::new(None), |
| 213 | 161 | ||
| @@ -450,9 +398,9 @@ impl SyncExecutor { | |||
| 450 | } | 398 | } |
| 451 | 399 | ||
| 452 | pub(super) unsafe fn spawn(&'static self, task: TaskRef) { | 400 | pub(super) unsafe fn spawn(&'static self, task: TaskRef) { |
| 453 | state::locked(|l| { | 401 | task.header() |
| 454 | task.header().executor.set(Some(self), l); | 402 | .executor |
| 455 | }); | 403 | .store((self as *const Self).cast_mut(), Ordering::Relaxed); |
| 456 | 404 | ||
| 457 | #[cfg(feature = "trace")] | 405 | #[cfg(feature = "trace")] |
| 458 | trace::task_new(self, &task); | 406 | trace::task_new(self, &task); |
| @@ -605,7 +553,7 @@ pub fn wake_task(task: TaskRef) { | |||
| 605 | header.state.run_enqueue(|l| { | 553 | header.state.run_enqueue(|l| { |
| 606 | // We have just marked the task as scheduled, so enqueue it. | 554 | // We have just marked the task as scheduled, so enqueue it. |
| 607 | unsafe { | 555 | unsafe { |
| 608 | let executor = header.executor.get(l).as_ref().unwrap_unchecked(); | 556 | let executor = header.executor.load(Ordering::Relaxed).as_ref().unwrap_unchecked(); |
| 609 | executor.enqueue(task, l); | 557 | executor.enqueue(task, l); |
| 610 | } | 558 | } |
| 611 | }); | 559 | }); |
| @@ -619,7 +567,7 @@ pub fn wake_task_no_pend(task: TaskRef) { | |||
| 619 | header.state.run_enqueue(|l| { | 567 | header.state.run_enqueue(|l| { |
| 620 | // We have just marked the task as scheduled, so enqueue it. | 568 | // We have just marked the task as scheduled, so enqueue it. |
| 621 | unsafe { | 569 | unsafe { |
| 622 | let executor = header.executor.get(l).as_ref().unwrap_unchecked(); | 570 | let executor = header.executor.load(Ordering::Relaxed).as_ref().unwrap_unchecked(); |
| 623 | executor.run_queue.enqueue(task, l); | 571 | executor.run_queue.enqueue(task, l); |
| 624 | } | 572 | } |
| 625 | }); | 573 | }); |
diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index bc243bee7..16347ad71 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | use core::future::poll_fn; | 1 | use core::future::poll_fn; |
| 2 | use core::marker::PhantomData; | 2 | use core::marker::PhantomData; |
| 3 | use core::mem; | 3 | use core::mem; |
| 4 | use core::sync::atomic::Ordering; | ||
| 4 | use core::task::Poll; | 5 | use core::task::Poll; |
| 5 | 6 | ||
| 6 | use super::raw; | 7 | use super::raw; |
| @@ -92,9 +93,13 @@ impl Spawner { | |||
| 92 | pub async fn for_current_executor() -> Self { | 93 | pub async fn for_current_executor() -> Self { |
| 93 | poll_fn(|cx| { | 94 | poll_fn(|cx| { |
| 94 | let task = raw::task_from_waker(cx.waker()); | 95 | let task = raw::task_from_waker(cx.waker()); |
| 95 | let executor = raw::state::locked(|l| { | 96 | let executor = unsafe { |
| 96 | unsafe { task.header().executor.get(l).as_ref().unwrap_unchecked() } | 97 | task.header() |
| 97 | }); | 98 | .executor |
| 99 | .load(Ordering::Relaxed) | ||
| 100 | .as_ref() | ||
| 101 | .unwrap_unchecked() | ||
| 102 | }; | ||
| 98 | let executor = unsafe { raw::Executor::wrap(executor) }; | 103 | let executor = unsafe { raw::Executor::wrap(executor) }; |
| 99 | Poll::Ready(Self::new(executor)) | 104 | Poll::Ready(Self::new(executor)) |
| 100 | }) | 105 | }) |
| @@ -166,9 +171,13 @@ impl SendSpawner { | |||
| 166 | pub async fn for_current_executor() -> Self { | 171 | pub async fn for_current_executor() -> Self { |
| 167 | poll_fn(|cx| { | 172 | poll_fn(|cx| { |
| 168 | let task = raw::task_from_waker(cx.waker()); | 173 | let task = raw::task_from_waker(cx.waker()); |
| 169 | let executor = raw::state::locked(|l| { | 174 | let executor = unsafe { |
| 170 | unsafe { task.header().executor.get(l).as_ref().unwrap_unchecked() } | 175 | task.header() |
| 171 | }); | 176 | .executor |
| 177 | .load(Ordering::Relaxed) | ||
| 178 | .as_ref() | ||
| 179 | .unwrap_unchecked() | ||
| 180 | }; | ||
| 172 | Poll::Ready(Self::new(executor)) | 181 | Poll::Ready(Self::new(executor)) |
| 173 | }) | 182 | }) |
| 174 | .await | 183 | .await |
