diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-02-26 02:04:48 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2021-02-26 02:04:48 +0100 |
| commit | da917791174510637c69660b10b1e201d22cfe9d (patch) | |
| tree | 263cd79b24c0d0c7df56b9bd1444aac777e64b7b | |
| parent | 17cf301d4fdc3bc0b1356ed250bfacca0d67ef3e (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.rs | 2 | ||||
| -rw-r--r-- | embassy-nrf/src/qspi.rs | 2 | ||||
| -rw-r--r-- | embassy-nrf/src/rtc.rs | 12 | ||||
| -rw-r--r-- | embassy-nrf/src/uarte.rs | 2 | ||||
| -rw-r--r-- | embassy-nrf/src/util/peripheral.rs | 18 | ||||
| -rw-r--r-- | embassy-stm32f4/src/rtc.rs | 12 | ||||
| -rw-r--r-- | embassy-stm32f4/src/serial.rs | 6 | ||||
| -rw-r--r-- | embassy/src/executor/mod.rs | 12 | ||||
| -rw-r--r-- | embassy/src/interrupt.rs | 8 | ||||
| -rw-r--r-- | embassy/src/util/signal.rs | 9 |
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> { | |||
| 93 | impl<'a, I: Interrupt> InterruptFuture<'a, I> { | 93 | impl<'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 { |
