aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-02-26 02:04:48 +0100
committerDario Nieuwenhuis <[email protected]>2021-02-26 02:04:48 +0100
commitda917791174510637c69660b10b1e201d22cfe9d (patch)
tree263cd79b24c0d0c7df56b9bd1444aac777e64b7b
parent17cf301d4fdc3bc0b1356ed250bfacca0d67ef3e (diff)
interrupt: Split set_handler context.
Since introducing the ctx pointer, the handler is now two words, so setting it can race with the interrupt firing. On race it's possible for the new handler to be alled with the old ctx pointer or viceversa. Rather than documenting this, it's better to split the function in two to make it obvious to the user that it's not atomic. The user can use a critical section, or disable/enable the interrupt to avoid races if this is a concern.
-rw-r--r--embassy-nrf/src/gpiote.rs2
-rw-r--r--embassy-nrf/src/qspi.rs2
-rw-r--r--embassy-nrf/src/rtc.rs12
-rw-r--r--embassy-nrf/src/uarte.rs2
-rw-r--r--embassy-nrf/src/util/peripheral.rs18
-rw-r--r--embassy-stm32f4/src/rtc.rs12
-rw-r--r--embassy-stm32f4/src/serial.rs6
-rw-r--r--embassy/src/executor/mod.rs12
-rw-r--r--embassy/src/interrupt.rs8
-rw-r--r--embassy/src/util/signal.rs9
10 files changed, 41 insertions, 42 deletions
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index 592ca82a7..01e61bd5c 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -118,7 +118,7 @@ impl Gpiote {
118 // Enable interrupts 118 // Enable interrupts
119 gpiote.events_port.write(|w| w); 119 gpiote.events_port.write(|w| w);
120 gpiote.intenset.write(|w| w.port().set()); 120 gpiote.intenset.write(|w| w.port().set());
121 irq.set_handler(Self::on_irq, core::ptr::null_mut()); 121 irq.set_handler(Self::on_irq);
122 irq.unpend(); 122 irq.unpend();
123 irq.enable(); 123 irq.enable();
124 124
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs
index 902d6511b..300b32ad5 100644
--- a/embassy-nrf/src/qspi.rs
+++ b/embassy-nrf/src/qspi.rs
@@ -146,7 +146,7 @@ impl Qspi {
146 SIGNAL.reset(); 146 SIGNAL.reset();
147 qspi.intenset.write(|w| w.ready().set()); 147 qspi.intenset.write(|w| w.ready().set());
148 148
149 irq.set_handler(irq_handler, core::ptr::null_mut()); 149 irq.set_handler(irq_handler);
150 irq.unpend(); 150 irq.unpend();
151 irq.enable(); 151 irq.enable();
152 152
diff --git a/embassy-nrf/src/rtc.rs b/embassy-nrf/src/rtc.rs
index 867c710c3..7a79580cc 100644
--- a/embassy-nrf/src/rtc.rs
+++ b/embassy-nrf/src/rtc.rs
@@ -109,13 +109,11 @@ impl<T: Instance> RTC<T> {
109 // Wait for clear 109 // Wait for clear
110 while self.rtc.counter.read().bits() != 0 {} 110 while self.rtc.counter.read().bits() != 0 {}
111 111
112 self.irq.set_handler( 112 self.irq.set_handler(|ptr| unsafe {
113 |ptr| unsafe { 113 let this = &*(ptr as *const () as *const Self);
114 let this = &*(ptr as *const () as *const Self); 114 this.on_interrupt();
115 this.on_interrupt(); 115 });
116 }, 116 self.irq.set_handler_context(self as *const _ as *mut _);
117 self as *const _ as *mut _,
118 );
119 self.irq.unpend(); 117 self.irq.unpend();
120 self.irq.enable(); 118 self.irq.enable();
121 } 119 }
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index f029276b2..07718a1dd 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -119,7 +119,7 @@ where
119 .write(|w| w.endtx().set().txstopped().set().endrx().set().rxto().set()); 119 .write(|w| w.endtx().set().txstopped().set().endrx().set().rxto().set());
120 120
121 // Register ISR 121 // Register ISR
122 irq.set_handler(Self::on_irq, core::ptr::null_mut()); 122 irq.set_handler(Self::on_irq);
123 irq.unpend(); 123 irq.unpend();
124 irq.enable(); 124 irq.enable();
125 125
diff --git a/embassy-nrf/src/util/peripheral.rs b/embassy-nrf/src/util/peripheral.rs
index 8cefaeef8..bf78d7760 100644
--- a/embassy-nrf/src/util/peripheral.rs
+++ b/embassy-nrf/src/util/peripheral.rs
@@ -33,16 +33,14 @@ impl<S: PeripheralState> PeripheralMutex<S> {
33 irq.disable(); 33 irq.disable();
34 compiler_fence(Ordering::SeqCst); 34 compiler_fence(Ordering::SeqCst);
35 35
36 irq.set_handler( 36 irq.set_handler(|p| {
37 |p| { 37 // Safety: it's OK to get a &mut to the state, since
38 // Safety: it's OK to get a &mut to the state, since 38 // - We're in the IRQ, no one else can't preempt us
39 // - We're in the IRQ, no one else can't preempt us 39 // - We can't have preempted a with() call because the irq is disabled during it.
40 // - We can't have preempted a with() call because the irq is disabled during it. 40 let state = unsafe { &mut *(p as *mut S) };
41 let state = unsafe { &mut *(p as *mut S) }; 41 state.on_interrupt();
42 state.on_interrupt(); 42 });
43 }, 43 irq.set_handler_context(state.get() as *mut ());
44 state.get() as *mut (),
45 );
46 44
47 // Safety: it's OK to get a &mut to the state, since the irq is disabled. 45 // Safety: it's OK to get a &mut to the state, since the irq is disabled.
48 let state = unsafe { &mut *state.get() }; 46 let state = unsafe { &mut *state.get() };
diff --git a/embassy-stm32f4/src/rtc.rs b/embassy-stm32f4/src/rtc.rs
index da7702876..21589f5d6 100644
--- a/embassy-stm32f4/src/rtc.rs
+++ b/embassy-stm32f4/src/rtc.rs
@@ -92,13 +92,11 @@ impl<T: Instance> RTC<T> {
92 self.rtc.set_compare(0, 0x8000); 92 self.rtc.set_compare(0, 0x8000);
93 self.rtc.set_compare_interrupt(0, true); 93 self.rtc.set_compare_interrupt(0, true);
94 94
95 self.irq.set_handler( 95 self.irq.set_handler(|ptr| unsafe {
96 |ptr| unsafe { 96 let this = &*(ptr as *const () as *const Self);
97 let this = &*(ptr as *const () as *const Self); 97 this.on_interrupt();
98 this.on_interrupt(); 98 });
99 }, 99 self.irq.set_handler_context(self as *const _ as *mut _);
100 self as *const _ as *mut _,
101 );
102 self.irq.unpend(); 100 self.irq.unpend();
103 self.irq.enable(); 101 self.irq.enable();
104 102
diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs
index d84d8cb01..669d7856c 100644
--- a/embassy-stm32f4/src/serial.rs
+++ b/embassy-stm32f4/src/serial.rs
@@ -70,9 +70,9 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
70 let (usart, _) = serial.release(); 70 let (usart, _) = serial.release();
71 71
72 // Register ISR 72 // Register ISR
73 tx_int.set_handler(Self::on_tx_irq, core::ptr::null_mut()); 73 tx_int.set_handler(Self::on_tx_irq);
74 rx_int.set_handler(Self::on_rx_irq, core::ptr::null_mut()); 74 rx_int.set_handler(Self::on_rx_irq);
75 usart_int.set_handler(Self::on_rx_irq, core::ptr::null_mut()); 75 usart_int.set_handler(Self::on_rx_irq);
76 // usart_int.unpend(); 76 // usart_int.unpend();
77 // usart_int.enable(); 77 // usart_int.enable();
78 78
diff --git a/embassy/src/executor/mod.rs b/embassy/src/executor/mod.rs
index 6c42764bb..be0d1b9e7 100644
--- a/embassy/src/executor/mod.rs
+++ b/embassy/src/executor/mod.rs
@@ -244,13 +244,11 @@ impl<I: Interrupt> IrqExecutor<I> {
244 244
245 init(unsafe { self.inner.spawner() }); 245 init(unsafe { self.inner.spawner() });
246 246
247 self.irq.set_handler( 247 self.irq.set_handler(|ctx| unsafe {
248 |ctx| unsafe { 248 let executor = &*(ctx as *const raw::Executor);
249 let executor = &*(ctx as *const raw::Executor); 249 executor.run_queued();
250 executor.run_queued(); 250 });
251 }, 251 self.irq.set_handler_context(&self.inner as *const _ as _);
252 &self.inner as *const _ as _,
253 );
254 self.irq.enable(); 252 self.irq.enable();
255 } 253 }
256} 254}
diff --git a/embassy/src/interrupt.rs b/embassy/src/interrupt.rs
index 9106def5f..53413d41d 100644
--- a/embassy/src/interrupt.rs
+++ b/embassy/src/interrupt.rs
@@ -38,10 +38,9 @@ pub unsafe trait Interrupt {
38 #[doc(hidden)] 38 #[doc(hidden)]
39 unsafe fn __handler(&self) -> &'static Handler; 39 unsafe fn __handler(&self) -> &'static Handler;
40 40
41 fn set_handler(&self, func: unsafe fn(*mut ()), ctx: *mut ()) { 41 fn set_handler(&self, func: unsafe fn(*mut ())) {
42 let handler = unsafe { self.__handler() }; 42 let handler = unsafe { self.__handler() };
43 handler.func.store(func as *mut (), Ordering::Release); 43 handler.func.store(func as *mut (), Ordering::Release);
44 handler.ctx.store(ctx, Ordering::Release);
45 } 44 }
46 45
47 fn remove_handler(&self) { 46 fn remove_handler(&self) {
@@ -49,6 +48,11 @@ pub unsafe trait Interrupt {
49 handler.func.store(ptr::null_mut(), Ordering::Release); 48 handler.func.store(ptr::null_mut(), Ordering::Release);
50 } 49 }
51 50
51 fn set_handler_context(&self, ctx: *mut ()) {
52 let handler = unsafe { self.__handler() };
53 handler.ctx.store(ctx, Ordering::Release);
54 }
55
52 #[inline] 56 #[inline]
53 fn enable(&self) { 57 fn enable(&self) {
54 unsafe { 58 unsafe {
diff --git a/embassy/src/util/signal.rs b/embassy/src/util/signal.rs
index 9fcfa7ac1..0abcc75f3 100644
--- a/embassy/src/util/signal.rs
+++ b/embassy/src/util/signal.rs
@@ -93,7 +93,8 @@ impl<'a, I: Interrupt> Drop for InterruptFuture<'a, I> {
93impl<'a, I: Interrupt> InterruptFuture<'a, I> { 93impl<'a, I: Interrupt> InterruptFuture<'a, I> {
94 pub fn new(interrupt: &'a mut I) -> Self { 94 pub fn new(interrupt: &'a mut I) -> Self {
95 interrupt.disable(); 95 interrupt.disable();
96 interrupt.set_handler(Self::interrupt_handler, ptr::null_mut()); 96 interrupt.set_handler(Self::interrupt_handler);
97 interrupt.set_handler_context(ptr::null_mut());
97 interrupt.unpend(); 98 interrupt.unpend();
98 interrupt.enable(); 99 interrupt.enable();
99 100
@@ -121,8 +122,10 @@ impl<'a, I: Interrupt> Future for InterruptFuture<'a, I> {
121 122
122 fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { 123 fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
123 let s = unsafe { self.get_unchecked_mut() }; 124 let s = unsafe { self.get_unchecked_mut() };
124 let ctx = unsafe { executor::raw::task_from_waker(&cx.waker()).cast().as_ptr() }; 125 s.interrupt.set_handler(Self::interrupt_handler);
125 s.interrupt.set_handler(Self::interrupt_handler, ctx); 126 s.interrupt.set_handler_context(unsafe {
127 executor::raw::task_from_waker(&cx.waker()).cast().as_ptr()
128 });
126 if s.interrupt.is_enabled() { 129 if s.interrupt.is_enabled() {
127 Poll::Pending 130 Poll::Pending
128 } else { 131 } else {