diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-11-14 22:32:48 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2023-11-15 18:43:27 +0100 |
| commit | bef9b7a8539c3dddb1cf6ab46db161f1ca56b1a1 (patch) | |
| tree | 6d15736eec0029c13093bee120bd2189aa9537ac /embassy-executor/src/raw/mod.rs | |
| parent | 50a983fd9b8f10fa5153757593e9f8cfccc902ac (diff) | |
executor: remove atomic-polyfill.
Diffstat (limited to 'embassy-executor/src/raw/mod.rs')
| -rw-r--r-- | embassy-executor/src/raw/mod.rs | 58 |
1 files changed, 15 insertions, 43 deletions
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 6d2c1c18a..ed0bedd25 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs | |||
| @@ -7,7 +7,14 @@ | |||
| 7 | //! Using this module requires respecting subtle safety contracts. If you can, prefer using the safe | 7 | //! Using this module requires respecting subtle safety contracts. If you can, prefer using the safe |
| 8 | //! [executor wrappers](crate::Executor) and the [`embassy_executor::task`](embassy_macros::task) macro, which are fully safe. | 8 | //! [executor wrappers](crate::Executor) and the [`embassy_executor::task`](embassy_macros::task) macro, which are fully safe. |
| 9 | 9 | ||
| 10 | #[cfg_attr(target_has_atomic = "ptr", path = "run_queue_atomics.rs")] | ||
| 11 | #[cfg_attr(not(target_has_atomic = "ptr"), path = "run_queue_critical_section.rs")] | ||
| 10 | mod run_queue; | 12 | mod run_queue; |
| 13 | |||
| 14 | #[cfg_attr(target_has_atomic = "8", path = "state_atomics.rs")] | ||
| 15 | #[cfg_attr(not(target_has_atomic = "8"), path = "state_critical_section.rs")] | ||
| 16 | mod state; | ||
| 17 | |||
| 11 | #[cfg(feature = "integrated-timers")] | 18 | #[cfg(feature = "integrated-timers")] |
| 12 | mod timer_queue; | 19 | mod timer_queue; |
| 13 | pub(crate) mod util; | 20 | pub(crate) mod util; |
| @@ -21,7 +28,6 @@ use core::pin::Pin; | |||
| 21 | use core::ptr::NonNull; | 28 | use core::ptr::NonNull; |
| 22 | use core::task::{Context, Poll}; | 29 | use core::task::{Context, Poll}; |
| 23 | 30 | ||
| 24 | use atomic_polyfill::{AtomicU32, Ordering}; | ||
| 25 | #[cfg(feature = "integrated-timers")] | 31 | #[cfg(feature = "integrated-timers")] |
| 26 | use embassy_time::driver::{self, AlarmHandle}; | 32 | use embassy_time::driver::{self, AlarmHandle}; |
| 27 | #[cfg(feature = "integrated-timers")] | 33 | #[cfg(feature = "integrated-timers")] |
| @@ -30,21 +36,14 @@ use embassy_time::Instant; | |||
| 30 | use rtos_trace::trace; | 36 | use rtos_trace::trace; |
| 31 | 37 | ||
| 32 | use self::run_queue::{RunQueue, RunQueueItem}; | 38 | use self::run_queue::{RunQueue, RunQueueItem}; |
| 39 | use self::state::State; | ||
| 33 | use self::util::{SyncUnsafeCell, UninitCell}; | 40 | use self::util::{SyncUnsafeCell, UninitCell}; |
| 34 | pub use self::waker::task_from_waker; | 41 | pub use self::waker::task_from_waker; |
| 35 | use super::SpawnToken; | 42 | use super::SpawnToken; |
| 36 | 43 | ||
| 37 | /// Task is spawned (has a future) | ||
| 38 | pub(crate) const STATE_SPAWNED: u32 = 1 << 0; | ||
| 39 | /// Task is in the executor run queue | ||
| 40 | pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1; | ||
| 41 | /// Task is in the executor timer queue | ||
| 42 | #[cfg(feature = "integrated-timers")] | ||
| 43 | pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; | ||
| 44 | |||
| 45 | /// Raw task header for use in task pointers. | 44 | /// Raw task header for use in task pointers. |
| 46 | pub(crate) struct TaskHeader { | 45 | pub(crate) struct TaskHeader { |
| 47 | pub(crate) state: AtomicU32, | 46 | pub(crate) state: State, |
| 48 | pub(crate) run_queue_item: RunQueueItem, | 47 | pub(crate) run_queue_item: RunQueueItem, |
| 49 | pub(crate) executor: SyncUnsafeCell<Option<&'static SyncExecutor>>, | 48 | pub(crate) executor: SyncUnsafeCell<Option<&'static SyncExecutor>>, |
| 50 | poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>, | 49 | poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>, |
| @@ -116,7 +115,7 @@ impl<F: Future + 'static> TaskStorage<F> { | |||
| 116 | pub const fn new() -> Self { | 115 | pub const fn new() -> Self { |
| 117 | Self { | 116 | Self { |
| 118 | raw: TaskHeader { | 117 | raw: TaskHeader { |
| 119 | state: AtomicU32::new(0), | 118 | state: State::new(), |
| 120 | run_queue_item: RunQueueItem::new(), | 119 | run_queue_item: RunQueueItem::new(), |
| 121 | executor: SyncUnsafeCell::new(None), | 120 | executor: SyncUnsafeCell::new(None), |
| 122 | // Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss` | 121 | // Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss` |
| @@ -161,7 +160,7 @@ impl<F: Future + 'static> TaskStorage<F> { | |||
| 161 | match future.poll(&mut cx) { | 160 | match future.poll(&mut cx) { |
| 162 | Poll::Ready(_) => { | 161 | Poll::Ready(_) => { |
| 163 | this.future.drop_in_place(); | 162 | this.future.drop_in_place(); |
| 164 | this.raw.state.fetch_and(!STATE_SPAWNED, Ordering::AcqRel); | 163 | this.raw.state.despawn(); |
| 165 | 164 | ||
| 166 | #[cfg(feature = "integrated-timers")] | 165 | #[cfg(feature = "integrated-timers")] |
| 167 | this.raw.expires_at.set(Instant::MAX); | 166 | this.raw.expires_at.set(Instant::MAX); |
| @@ -193,11 +192,7 @@ impl<F: Future + 'static> AvailableTask<F> { | |||
| 193 | /// | 192 | /// |
| 194 | /// This function returns `None` if a task has already been spawned and has not finished running. | 193 | /// This function returns `None` if a task has already been spawned and has not finished running. |
| 195 | pub fn claim(task: &'static TaskStorage<F>) -> Option<Self> { | 194 | pub fn claim(task: &'static TaskStorage<F>) -> Option<Self> { |
| 196 | task.raw | 195 | task.raw.state.spawn().then(|| Self { task }) |
| 197 | .state | ||
| 198 | .compare_exchange(0, STATE_SPAWNED | STATE_RUN_QUEUED, Ordering::AcqRel, Ordering::Acquire) | ||
| 199 | .ok() | ||
| 200 | .map(|_| Self { task }) | ||
| 201 | } | 196 | } |
| 202 | 197 | ||
| 203 | fn initialize_impl<S>(self, future: impl FnOnce() -> F) -> SpawnToken<S> { | 198 | fn initialize_impl<S>(self, future: impl FnOnce() -> F) -> SpawnToken<S> { |
| @@ -394,8 +389,7 @@ impl SyncExecutor { | |||
| 394 | #[cfg(feature = "integrated-timers")] | 389 | #[cfg(feature = "integrated-timers")] |
| 395 | task.expires_at.set(Instant::MAX); | 390 | task.expires_at.set(Instant::MAX); |
| 396 | 391 | ||
| 397 | let state = task.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel); | 392 | if !task.state.run_dequeue() { |
| 398 | if state & STATE_SPAWNED == 0 { | ||
| 399 | // If task is not running, ignore it. This can happen in the following scenario: | 393 | // If task is not running, ignore it. This can happen in the following scenario: |
| 400 | // - Task gets dequeued, poll starts | 394 | // - Task gets dequeued, poll starts |
| 401 | // - While task is being polled, it gets woken. It gets placed in the queue. | 395 | // - While task is being polled, it gets woken. It gets placed in the queue. |
| @@ -546,18 +540,7 @@ impl Executor { | |||
| 546 | /// You can obtain a `TaskRef` from a `Waker` using [`task_from_waker`]. | 540 | /// You can obtain a `TaskRef` from a `Waker` using [`task_from_waker`]. |
| 547 | pub fn wake_task(task: TaskRef) { | 541 | pub fn wake_task(task: TaskRef) { |
| 548 | let header = task.header(); | 542 | let header = task.header(); |
| 549 | 543 | if header.state.run_enqueue() { | |
| 550 | let res = header.state.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| { | ||
| 551 | // If already scheduled, or if not started, | ||
| 552 | if (state & STATE_RUN_QUEUED != 0) || (state & STATE_SPAWNED == 0) { | ||
| 553 | None | ||
| 554 | } else { | ||
| 555 | // Mark it as scheduled | ||
| 556 | Some(state | STATE_RUN_QUEUED) | ||
| 557 | } | ||
| 558 | }); | ||
| 559 | |||
| 560 | if res.is_ok() { | ||
| 561 | // We have just marked the task as scheduled, so enqueue it. | 544 | // We have just marked the task as scheduled, so enqueue it. |
| 562 | unsafe { | 545 | unsafe { |
| 563 | let executor = header.executor.get().unwrap_unchecked(); | 546 | let executor = header.executor.get().unwrap_unchecked(); |
| @@ -571,18 +554,7 @@ pub fn wake_task(task: TaskRef) { | |||
| 571 | /// You can obtain a `TaskRef` from a `Waker` using [`task_from_waker`]. | 554 | /// You can obtain a `TaskRef` from a `Waker` using [`task_from_waker`]. |
| 572 | pub fn wake_task_no_pend(task: TaskRef) { | 555 | pub fn wake_task_no_pend(task: TaskRef) { |
| 573 | let header = task.header(); | 556 | let header = task.header(); |
| 574 | 557 | if header.state.run_enqueue() { | |
| 575 | let res = header.state.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| { | ||
| 576 | // If already scheduled, or if not started, | ||
| 577 | if (state & STATE_RUN_QUEUED != 0) || (state & STATE_SPAWNED == 0) { | ||
| 578 | None | ||
| 579 | } else { | ||
| 580 | // Mark it as scheduled | ||
| 581 | Some(state | STATE_RUN_QUEUED) | ||
| 582 | } | ||
| 583 | }); | ||
| 584 | |||
| 585 | if res.is_ok() { | ||
| 586 | // We have just marked the task as scheduled, so enqueue it. | 558 | // We have just marked the task as scheduled, so enqueue it. |
| 587 | unsafe { | 559 | unsafe { |
| 588 | let executor = header.executor.get().unwrap_unchecked(); | 560 | let executor = header.executor.get().unwrap_unchecked(); |
