aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor
diff options
context:
space:
mode:
authorDániel Buga <[email protected]>2024-12-16 17:24:17 +0100
committerDániel Buga <[email protected]>2024-12-16 17:29:07 +0100
commitb47a631abf0c200c3b29b8e4ec199421835a0525 (patch)
tree4eacf2103588ac1b1df52f6fe233fa787715d78d /embassy-executor
parentb44ef5ccb40d6b778e623e6e68a234c2e0615d25 (diff)
Rely on atomic load-store on all targets
Diffstat (limited to 'embassy-executor')
-rw-r--r--embassy-executor/src/raw/mod.rs72
-rw-r--r--embassy-executor/src/spawner.rs21
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")]
17pub(crate) mod state; 17mod state;
18
19#[cfg(target_has_atomic = "ptr")]
20mod 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"))]
43mod 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
70pub mod timer_queue; 19pub mod timer_queue;
71#[cfg(feature = "trace")] 20#[cfg(feature = "trace")]
@@ -79,10 +28,9 @@ use core::marker::PhantomData;
79use core::mem; 28use core::mem;
80use core::pin::Pin; 29use core::pin::Pin;
81use core::ptr::NonNull; 30use core::ptr::NonNull;
31use core::sync::atomic::{AtomicPtr, Ordering};
82use core::task::{Context, Poll}; 32use core::task::{Context, Poll};
83 33
84use crate::raw::owner::ExecutorRef;
85
86use self::run_queue::{RunQueue, RunQueueItem}; 34use self::run_queue::{RunQueue, RunQueueItem};
87use self::state::State; 35use self::state::State;
88use self::util::{SyncUnsafeCell, UninitCell}; 36use self::util::{SyncUnsafeCell, UninitCell};
@@ -93,7 +41,7 @@ use super::SpawnToken;
93pub(crate) struct TaskHeader { 41pub(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 @@
1use core::future::poll_fn; 1use core::future::poll_fn;
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::mem; 3use core::mem;
4use core::sync::atomic::Ordering;
4use core::task::Poll; 5use core::task::Poll;
5 6
6use super::raw; 7use 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