diff options
| author | Liam Murphy <[email protected]> | 2021-07-29 15:11:26 +1000 |
|---|---|---|
| committer | Liam Murphy <[email protected]> | 2021-07-29 15:11:26 +1000 |
| commit | d5ba35424d7eef2cc0c501758d214ce3a6febfc1 (patch) | |
| tree | 8d3b07073b7f5f2ea67bb061a990b019c79aeeb5 /embassy-extras/src/peripheral_shared.rs | |
| parent | 4d9514cbcb97343c3a75bfa565d753c44c2a0e27 (diff) | |
Replace `PeripheralStateUnchecked` with `register_interrupt_unchecked`
Diffstat (limited to 'embassy-extras/src/peripheral_shared.rs')
| -rw-r--r-- | embassy-extras/src/peripheral_shared.rs | 52 |
1 files changed, 33 insertions, 19 deletions
diff --git a/embassy-extras/src/peripheral_shared.rs b/embassy-extras/src/peripheral_shared.rs index 788ac3f96..71d746341 100644 --- a/embassy-extras/src/peripheral_shared.rs +++ b/embassy-extras/src/peripheral_shared.rs | |||
| @@ -5,30 +5,19 @@ use embassy::interrupt::{Interrupt, InterruptExt}; | |||
| 5 | 5 | ||
| 6 | use crate::peripheral::can_be_preempted; | 6 | use crate::peripheral::can_be_preempted; |
| 7 | 7 | ||
| 8 | /// A version of `PeripheralState` without the `'static` bound, | ||
| 9 | /// for cases where the compiler can't statically make sure | ||
| 10 | /// that `on_interrupt` doesn't reference anything which might be invalidated. | ||
| 11 | /// | ||
| 12 | /// # Safety | ||
| 13 | /// When types implementing this trait are used with `Peripheral`, | ||
| 14 | /// no fields referenced by `on_interrupt`'s lifetimes must end without first calling `Drop` on the `Peripheral`. | ||
| 15 | pub unsafe trait PeripheralStateUnchecked: Sync { | ||
| 16 | type Interrupt: Interrupt; | ||
| 17 | fn on_interrupt(&self); | ||
| 18 | } | ||
| 19 | |||
| 20 | /// A type which can be used as state with `Peripheral`. | 8 | /// A type which can be used as state with `Peripheral`. |
| 21 | /// | 9 | /// |
| 22 | /// It needs to be `Sync` because references are shared between the 'thread' which owns the `Peripheral` and the interrupt. | 10 | /// It needs to be `Sync` because references are shared between the 'thread' which owns the `Peripheral` and the interrupt. |
| 23 | /// | 11 | /// |
| 24 | /// It also requires `'static`, because although `Pin` guarantees that the memory of the state won't be invalidated, | 12 | /// It also requires `'static` to be used safely with `Peripheral::register_interrupt`, |
| 13 | /// because although `Pin` guarantees that the memory of the state won't be invalidated, | ||
| 25 | /// it doesn't guarantee that the lifetime will last. | 14 | /// it doesn't guarantee that the lifetime will last. |
| 26 | pub trait PeripheralState: Sync + 'static { | 15 | pub trait PeripheralState: Sync { |
| 27 | type Interrupt: Interrupt; | 16 | type Interrupt: Interrupt; |
| 28 | fn on_interrupt(&self); | 17 | fn on_interrupt(&self); |
| 29 | } | 18 | } |
| 30 | 19 | ||
| 31 | pub struct Peripheral<S: PeripheralStateUnchecked> { | 20 | pub struct Peripheral<S: PeripheralState> { |
| 32 | state: S, | 21 | state: S, |
| 33 | 22 | ||
| 34 | irq_setup_done: bool, | 23 | irq_setup_done: bool, |
| @@ -38,7 +27,24 @@ pub struct Peripheral<S: PeripheralStateUnchecked> { | |||
| 38 | _pinned: PhantomPinned, | 27 | _pinned: PhantomPinned, |
| 39 | } | 28 | } |
| 40 | 29 | ||
| 41 | impl<S: PeripheralStateUnchecked> Peripheral<S> { | 30 | impl<S: PeripheralState + 'static> Peripheral<S> { |
| 31 | /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it. | ||
| 32 | /// | ||
| 33 | /// This requires this `Peripheral`'s `PeripheralState` to live for `'static`, | ||
| 34 | /// because `Pin` only guarantees that it's memory won't be repurposed, | ||
| 35 | /// not that it's lifetime will last. | ||
| 36 | /// | ||
| 37 | /// To use non-`'static` `PeripheralState`, use the unsafe `register_interrupt_unchecked`. | ||
| 38 | /// | ||
| 39 | /// Note: `'static` doesn't mean it _has_ to live for the entire program, like an `&'static T`; | ||
| 40 | /// it just means it _can_ live for the entire program - for example, `u8` lives for `'static`. | ||
| 41 | pub fn register_interrupt(self: Pin<&mut Self>) { | ||
| 42 | // SAFETY: `S: 'static`, so there's no way it's lifetime can expire. | ||
| 43 | unsafe { self.register_interrupt_unchecked() } | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | impl<S: PeripheralState> Peripheral<S> { | ||
| 42 | pub fn new(irq: S::Interrupt, state: S) -> Self { | 48 | pub fn new(irq: S::Interrupt, state: S) -> Self { |
| 43 | if can_be_preempted(&irq) { | 49 | if can_be_preempted(&irq) { |
| 44 | panic!("`Peripheral` cannot be created in an interrupt with higher priority than the interrupt it wraps"); | 50 | panic!("`Peripheral` cannot be created in an interrupt with higher priority than the interrupt it wraps"); |
| @@ -54,8 +60,16 @@ impl<S: PeripheralStateUnchecked> Peripheral<S> { | |||
| 54 | } | 60 | } |
| 55 | } | 61 | } |
| 56 | 62 | ||
| 57 | pub fn register_interrupt(self: Pin<&mut Self>) { | 63 | /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it. |
| 58 | let this = unsafe { self.get_unchecked_mut() }; | 64 | /// |
| 65 | /// # Safety | ||
| 66 | /// The lifetime of any data in `PeripheralState` that is accessed by the interrupt handler | ||
| 67 | /// must not end without `Drop` being called on this `Peripheral`. | ||
| 68 | /// | ||
| 69 | /// This can be accomplished by either not accessing any data with a lifetime in `on_interrupt`, | ||
| 70 | /// or making sure that nothing like `mem::forget` is used on the `Peripheral`. | ||
| 71 | pub unsafe fn register_interrupt_unchecked(self: Pin<&mut Self>) { | ||
| 72 | let this = self.get_unchecked_mut(); | ||
| 59 | if this.irq_setup_done { | 73 | if this.irq_setup_done { |
| 60 | return; | 74 | return; |
| 61 | } | 75 | } |
| @@ -100,7 +114,7 @@ impl<S: PeripheralStateUnchecked> Peripheral<S> { | |||
| 100 | } | 114 | } |
| 101 | } | 115 | } |
| 102 | 116 | ||
| 103 | impl<S: PeripheralStateUnchecked> Drop for Peripheral<S> { | 117 | impl<S: PeripheralState> Drop for Peripheral<S> { |
| 104 | fn drop(&mut self) { | 118 | fn drop(&mut self) { |
| 105 | self.irq.disable(); | 119 | self.irq.disable(); |
| 106 | self.irq.remove_handler(); | 120 | self.irq.remove_handler(); |
