diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2023-05-14 22:20:15 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-05-14 22:20:15 +0000 |
| commit | 6e93d193cfdd2982410e106c383ecc1f066fccfb (patch) | |
| tree | 4000d4e8ef8f2883429cb4c5cde07bba8a53b520 /embassy-executor/src | |
| parent | 4567eff78ed486cea623f0864c3c10d6e528ae64 (diff) | |
| parent | 5fe36b6bb05f0460e12c726ab5554c9b4bad1829 (diff) | |
Merge #1451
1451: Work around xtensa deadlock, take 2 r=Dirbaio a=bugadani
This PR is another go at trying to do something with #1449. The commit was part of the previous attempt but mistakenly discarded as I still experienced lockups. However, after further testing, it looks like that lockup is caused by something else.
This is a manual, "cpu-local" critical section impl that should be good enough on dual-core CPUs, although the implementation still contains `SIGNAL_WORK_THREAD_MODE` which is absolutely not correct on dual-core. This approach was chosen because:
- not taking the global lock technically allows the second core to run
- wrapping the signal read and the sleep in a critical section prevents a race condition that would cause the CPU to sleep longer than ideal if an interrupt hits after reading, but before sleeping.
Co-authored-by: Dániel Buga <[email protected]>
Diffstat (limited to 'embassy-executor/src')
| -rw-r--r-- | embassy-executor/src/arch/xtensa.rs | 32 |
1 files changed, 20 insertions, 12 deletions
diff --git a/embassy-executor/src/arch/xtensa.rs b/embassy-executor/src/arch/xtensa.rs index 61ea92c16..017b2c52b 100644 --- a/embassy-executor/src/arch/xtensa.rs +++ b/embassy-executor/src/arch/xtensa.rs | |||
| @@ -63,21 +63,29 @@ mod thread { | |||
| 63 | loop { | 63 | loop { |
| 64 | unsafe { | 64 | unsafe { |
| 65 | self.inner.poll(); | 65 | self.inner.poll(); |
| 66 | |||
| 67 | // Manual critical section implementation that only masks interrupts handlers. | ||
| 68 | // We must not acquire the cross-core on dual-core systems because that would | ||
| 69 | // prevent the other core from doing useful work while this core is sleeping. | ||
| 70 | let token: critical_section::RawRestoreState; | ||
| 71 | core::arch::asm!("rsil {0}, 5", out(reg) token); | ||
| 72 | |||
| 66 | // we do not care about race conditions between the load and store operations, interrupts | 73 | // we do not care about race conditions between the load and store operations, interrupts |
| 67 | // will only set this value to true. | 74 | // will only set this value to true. |
| 68 | // if there is work to do, loop back to polling | 75 | // if there is work to do, loop back to polling |
| 69 | // TODO can we relax this? | 76 | if SIGNAL_WORK_THREAD_MODE.load(Ordering::SeqCst) { |
| 70 | critical_section::with(|_| { | 77 | SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst); |
| 71 | if SIGNAL_WORK_THREAD_MODE.load(Ordering::SeqCst) { | 78 | |
| 72 | SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst); | 79 | core::arch::asm!( |
| 73 | } else { | 80 | "wsr.ps {0}", |
| 74 | // waiti sets the PS.INTLEVEL when slipping into sleep | 81 | "rsync", in(reg) token) |
| 75 | // because critical sections in Xtensa are implemented via increasing | 82 | } else { |
| 76 | // PS.INTLEVEL the critical section ends here | 83 | // waiti sets the PS.INTLEVEL when slipping into sleep |
| 77 | // take care not add code after `waiti` if it needs to be inside the CS | 84 | // because critical sections in Xtensa are implemented via increasing |
| 78 | core::arch::asm!("waiti 0"); // critical section ends here | 85 | // PS.INTLEVEL the critical section ends here |
| 79 | } | 86 | // take care not add code after `waiti` if it needs to be inside the CS |
| 80 | }); | 87 | core::arch::asm!("waiti 0"); // critical section ends here |
| 88 | } | ||
| 81 | } | 89 | } |
| 82 | } | 90 | } |
| 83 | } | 91 | } |
