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 <bugadani@gmail.com>
This commit is contained in:
commit
6e93d193cf
@ -63,21 +63,29 @@ mod thread {
|
|||||||
loop {
|
loop {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.inner.poll();
|
self.inner.poll();
|
||||||
|
|
||||||
|
// Manual critical section implementation that only masks interrupts handlers.
|
||||||
|
// We must not acquire the cross-core on dual-core systems because that would
|
||||||
|
// prevent the other core from doing useful work while this core is sleeping.
|
||||||
|
let token: critical_section::RawRestoreState;
|
||||||
|
core::arch::asm!("rsil {0}, 5", out(reg) token);
|
||||||
|
|
||||||
// we do not care about race conditions between the load and store operations, interrupts
|
// we do not care about race conditions between the load and store operations, interrupts
|
||||||
// will only set this value to true.
|
// will only set this value to true.
|
||||||
// if there is work to do, loop back to polling
|
// if there is work to do, loop back to polling
|
||||||
// TODO can we relax this?
|
if SIGNAL_WORK_THREAD_MODE.load(Ordering::SeqCst) {
|
||||||
critical_section::with(|_| {
|
SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst);
|
||||||
if SIGNAL_WORK_THREAD_MODE.load(Ordering::SeqCst) {
|
|
||||||
SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst);
|
core::arch::asm!(
|
||||||
} else {
|
"wsr.ps {0}",
|
||||||
// waiti sets the PS.INTLEVEL when slipping into sleep
|
"rsync", in(reg) token)
|
||||||
// because critical sections in Xtensa are implemented via increasing
|
} else {
|
||||||
// PS.INTLEVEL the critical section ends here
|
// waiti sets the PS.INTLEVEL when slipping into sleep
|
||||||
// take care not add code after `waiti` if it needs to be inside the CS
|
// because critical sections in Xtensa are implemented via increasing
|
||||||
core::arch::asm!("waiti 0"); // critical section ends here
|
// PS.INTLEVEL the critical section ends here
|
||||||
}
|
// take care not add code after `waiti` if it needs to be inside the CS
|
||||||
});
|
core::arch::asm!("waiti 0"); // critical section ends here
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user