aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2023-05-14 22:20:15 +0000
committerGitHub <[email protected]>2023-05-14 22:20:15 +0000
commit6e93d193cfdd2982410e106c383ecc1f066fccfb (patch)
tree4000d4e8ef8f2883429cb4c5cde07bba8a53b520 /embassy-executor/src
parent4567eff78ed486cea623f0864c3c10d6e528ae64 (diff)
parent5fe36b6bb05f0460e12c726ab5554c9b4bad1829 (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.rs32
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 }