diff options
| author | Dániel Buga <[email protected]> | 2024-12-13 20:35:40 +0100 |
|---|---|---|
| committer | Dániel Buga <[email protected]> | 2024-12-16 15:28:19 +0100 |
| commit | f389ba37219d842d7db0ab94cd421c69645a5757 (patch) | |
| tree | bee175817d7dc3119c5533bd78069cd6ce0a7f44 /embassy-executor/src/raw/state_atomics_arm.rs | |
| parent | 2c3bc75da6008afa7cacc1045954cef7e3d8740f (diff) | |
Only lock once to wake a task
Diffstat (limited to 'embassy-executor/src/raw/state_atomics_arm.rs')
| -rw-r--r-- | embassy-executor/src/raw/state_atomics_arm.rs | 19 |
1 files changed, 15 insertions, 4 deletions
diff --git a/embassy-executor/src/raw/state_atomics_arm.rs b/embassy-executor/src/raw/state_atomics_arm.rs index 7a152e8c0..f0f014652 100644 --- a/embassy-executor/src/raw/state_atomics_arm.rs +++ b/embassy-executor/src/raw/state_atomics_arm.rs | |||
| @@ -3,6 +3,15 @@ use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; | |||
| 3 | 3 | ||
| 4 | use super::timer_queue::TimerEnqueueOperation; | 4 | use super::timer_queue::TimerEnqueueOperation; |
| 5 | 5 | ||
| 6 | pub(crate) struct Token(()); | ||
| 7 | |||
| 8 | /// Creates a token and passes it to the closure. | ||
| 9 | /// | ||
| 10 | /// This is a no-op replacement for `CriticalSection::with` because we don't need any locking. | ||
| 11 | pub(crate) fn locked(f: impl FnOnce(Token)) { | ||
| 12 | f(Token(())); | ||
| 13 | } | ||
| 14 | |||
| 6 | // Must be kept in sync with the layout of `State`! | 15 | // Must be kept in sync with the layout of `State`! |
| 7 | pub(crate) const STATE_SPAWNED: u32 = 1 << 0; | 16 | pub(crate) const STATE_SPAWNED: u32 = 1 << 0; |
| 8 | pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 8; | 17 | pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 8; |
| @@ -57,9 +66,10 @@ impl State { | |||
| 57 | self.spawned.store(false, Ordering::Relaxed); | 66 | self.spawned.store(false, Ordering::Relaxed); |
| 58 | } | 67 | } |
| 59 | 68 | ||
| 60 | /// Mark the task as run-queued if it's spawned and isn't already run-queued. Return true on success. | 69 | /// Mark the task as run-queued if it's spawned and isn't already run-queued. Run the given |
| 70 | /// function if the task was successfully marked. | ||
| 61 | #[inline(always)] | 71 | #[inline(always)] |
| 62 | pub fn run_enqueue(&self) -> bool { | 72 | pub fn run_enqueue(&self, f: impl FnOnce(Token)) { |
| 63 | unsafe { | 73 | unsafe { |
| 64 | loop { | 74 | loop { |
| 65 | let state: u32; | 75 | let state: u32; |
| @@ -67,14 +77,15 @@ impl State { | |||
| 67 | 77 | ||
| 68 | if (state & STATE_RUN_QUEUED != 0) || (state & STATE_SPAWNED == 0) { | 78 | if (state & STATE_RUN_QUEUED != 0) || (state & STATE_SPAWNED == 0) { |
| 69 | asm!("clrex", options(nomem, nostack)); | 79 | asm!("clrex", options(nomem, nostack)); |
| 70 | return false; | 80 | return; |
| 71 | } | 81 | } |
| 72 | 82 | ||
| 73 | let outcome: usize; | 83 | let outcome: usize; |
| 74 | let new_state = state | STATE_RUN_QUEUED; | 84 | let new_state = state | STATE_RUN_QUEUED; |
| 75 | asm!("strex {}, {}, [{}]", out(reg) outcome, in(reg) new_state, in(reg) self, options(nostack)); | 85 | asm!("strex {}, {}, [{}]", out(reg) outcome, in(reg) new_state, in(reg) self, options(nostack)); |
| 76 | if outcome == 0 { | 86 | if outcome == 0 { |
| 77 | return true; | 87 | locked(f); |
| 88 | return; | ||
| 78 | } | 89 | } |
| 79 | } | 90 | } |
| 80 | } | 91 | } |
