nrf/gpiote: fix irq race condition

The interrupt could fire between checking if sense=disabled and registering the waker,
in which case the future would get stuck.
This commit is contained in:
Dario Nieuwenhuis 2021-03-27 02:08:01 +01:00
parent 4ce46df160
commit 1c9f98e1b6
2 changed files with 10 additions and 15 deletions

View File

@ -395,9 +395,8 @@ pub struct PortInputFuture<'a> {
impl<'a> Drop for PortInputFuture<'a> { impl<'a> Drop for PortInputFuture<'a> {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { AnyPin::steal(self.pin_port) } let pin = unsafe { AnyPin::steal(self.pin_port) };
.conf() pin.conf().modify(|_, w| w.sense().disabled());
.modify(|_, w| w.sense().disabled());
} }
} }
@ -405,18 +404,13 @@ impl<'a> Future for PortInputFuture<'a> {
type Output = (); type Output = ();
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let dis = unsafe { AnyPin::steal(self.pin_port) }
.conf()
.read()
.sense()
.is_disabled();
if dis {
return Poll::Ready(());
}
PORT_WAKERS[self.pin_port as usize].register(cx.waker()); PORT_WAKERS[self.pin_port as usize].register(cx.waker());
Poll::Pending let pin = unsafe { AnyPin::steal(self.pin_port) };
if pin.conf().read().sense().is_disabled() {
Poll::Ready(())
} else {
Poll::Pending
}
} }
} }

View File

@ -1,7 +1,7 @@
use core::ptr::{self, NonNull}; use core::ptr::{self, NonNull};
use core::task::Waker; use core::task::Waker;
use atomic_polyfill::{AtomicPtr, Ordering}; use atomic_polyfill::{compiler_fence, AtomicPtr, Ordering};
use crate::executor::raw::{task_from_waker, wake_task, TaskHeader}; use crate::executor::raw::{task_from_waker, wake_task, TaskHeader};
@ -63,6 +63,7 @@ impl AtomicWaker {
pub fn register(&self, w: &Waker) { pub fn register(&self, w: &Waker) {
let w = unsafe { task_from_waker(w) }; let w = unsafe { task_from_waker(w) };
self.waker.store(w.as_ptr(), Ordering::Relaxed); self.waker.store(w.as_ptr(), Ordering::Relaxed);
compiler_fence(Ordering::SeqCst);
} }
/// Wake the registered waker, if any. /// Wake the registered waker, if any.