diff options
| author | Liam Murphy <[email protected]> | 2021-07-28 21:31:31 +1000 |
|---|---|---|
| committer | Liam Murphy <[email protected]> | 2021-07-28 21:31:31 +1000 |
| commit | 68c93256bcab8dfe0f65c694fa5fadb890fd3f00 (patch) | |
| tree | d76ddc56ac3f4caeef279919b5aca000aed2dc0e /embassy-extras | |
| parent | a6fea3cb28f717627bd8858016622270c3e76721 (diff) | |
fix: interrupts with equal priority can't preempt each other
Diffstat (limited to 'embassy-extras')
| -rw-r--r-- | embassy-extras/src/peripheral.rs | 28 |
1 files changed, 4 insertions, 24 deletions
diff --git a/embassy-extras/src/peripheral.rs b/embassy-extras/src/peripheral.rs index 2402ba9eb..396ab5432 100644 --- a/embassy-extras/src/peripheral.rs +++ b/embassy-extras/src/peripheral.rs | |||
| @@ -21,7 +21,7 @@ pub unsafe trait PeripheralStateUnchecked: Send { | |||
| 21 | /// A type which can be used as state with `PeripheralMutex`. | 21 | /// A type which can be used as state with `PeripheralMutex`. |
| 22 | /// | 22 | /// |
| 23 | /// It needs to be `Send` because `&mut` references are sent back and forth between the 'thread' which owns the `PeripheralMutex` and the interrupt, | 23 | /// It needs to be `Send` because `&mut` references are sent back and forth between the 'thread' which owns the `PeripheralMutex` and the interrupt, |
| 24 | /// and `&mut T` is `Send` where `T: Send`. | 24 | /// and `&mut T` is only `Send` where `T: Send`. |
| 25 | /// | 25 | /// |
| 26 | /// It also requires `'static`, because although `Pin` guarantees that the memory of the state won't be invalidated, | 26 | /// It also requires `'static`, because although `Pin` guarantees that the memory of the state won't be invalidated, |
| 27 | /// it doesn't guarantee that the lifetime will last. | 27 | /// it doesn't guarantee that the lifetime will last. |
| @@ -73,23 +73,13 @@ fn exception_to_system_handler(exception: Exception) -> Option<SystemHandler> { | |||
| 73 | /// Whether `irq` can be preempted by the current interrupt. | 73 | /// Whether `irq` can be preempted by the current interrupt. |
| 74 | pub(crate) fn can_be_preempted(irq: &impl Interrupt) -> bool { | 74 | pub(crate) fn can_be_preempted(irq: &impl Interrupt) -> bool { |
| 75 | match SCB::vect_active() { | 75 | match SCB::vect_active() { |
| 76 | // Thread mode can't preempt each other | 76 | // Thread mode can't preempt anything |
| 77 | VectActive::ThreadMode => false, | 77 | VectActive::ThreadMode => false, |
| 78 | VectActive::Exception(exception) => { | 78 | VectActive::Exception(exception) => { |
| 79 | // `SystemHandler` is a subset of `Exception` for those with configurable priority. | 79 | // `SystemHandler` is a subset of `Exception` for those with configurable priority. |
| 80 | // There's no built in way to convert between them, so `exception_to_system_handler` was necessary. | 80 | // There's no built in way to convert between them, so `exception_to_system_handler` was necessary. |
| 81 | if let Some(system_handler) = exception_to_system_handler(exception) { | 81 | if let Some(system_handler) = exception_to_system_handler(exception) { |
| 82 | let current_prio = SCB::get_priority(system_handler); | 82 | SCB::get_priority(system_handler) < irq.get_priority().into() |
| 83 | let irq_prio = irq.get_priority().into(); | ||
| 84 | if current_prio < irq_prio { | ||
| 85 | true | ||
| 86 | } else if current_prio == irq_prio { | ||
| 87 | // When multiple interrupts have the same priority number, | ||
| 88 | // the pending interrupt with the lowest interrupt number takes precedence. | ||
| 89 | (exception.irqn() as i16) < irq.number() as i16 | ||
| 90 | } else { | ||
| 91 | false | ||
| 92 | } | ||
| 93 | } else { | 83 | } else { |
| 94 | // There's no safe way I know of to maintain `!Send` state across invocations of HardFault or NMI, so that should be fine. | 84 | // There's no safe way I know of to maintain `!Send` state across invocations of HardFault or NMI, so that should be fine. |
| 95 | false | 85 | false |
| @@ -103,17 +93,7 @@ pub(crate) fn can_be_preempted(irq: &impl Interrupt) -> bool { | |||
| 103 | self.0 | 93 | self.0 |
| 104 | } | 94 | } |
| 105 | } | 95 | } |
| 106 | let current_prio = NVIC::get_priority(NrWrap(irqn.into())); | 96 | NVIC::get_priority(NrWrap(irqn.into())) < irq.get_priority().into() |
| 107 | let irq_prio = irq.get_priority().into(); | ||
| 108 | if current_prio < irq_prio { | ||
| 109 | true | ||
| 110 | } else if current_prio == irq_prio { | ||
| 111 | // When multiple interrupts have the same priority number, | ||
| 112 | // the pending interrupt with the lowest interrupt number takes precedence. | ||
| 113 | (irqn as u16) < irq.number() | ||
| 114 | } else { | ||
| 115 | false | ||
| 116 | } | ||
| 117 | } | 97 | } |
| 118 | } | 98 | } |
| 119 | } | 99 | } |
