aboutsummaryrefslogtreecommitdiff
path: root/embassy-hal-common
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-07-29 14:08:32 +0200
committerDario Nieuwenhuis <[email protected]>2021-08-02 19:55:04 +0200
commitaf87031d62ca9ee5e7dd44cba297f3d171ec0708 (patch)
tree82f43b826d016c0a2b9a86ec6f27a1f0d5fd63d5 /embassy-hal-common
parentde207764aee0dd9c23bd02f92b55a55babd47b1a (diff)
hal-common: remove Pin in PeripheralMutex
Diffstat (limited to 'embassy-hal-common')
-rw-r--r--embassy-hal-common/src/peripheral.rs124
-rw-r--r--embassy-hal-common/src/usb/mod.rs49
-rw-r--r--embassy-hal-common/src/usb/usb_serial.rs10
3 files changed, 91 insertions, 92 deletions
diff --git a/embassy-hal-common/src/peripheral.rs b/embassy-hal-common/src/peripheral.rs
index 92512a0f6..d3df06e86 100644
--- a/embassy-hal-common/src/peripheral.rs
+++ b/embassy-hal-common/src/peripheral.rs
@@ -1,6 +1,5 @@
1use core::cell::UnsafeCell; 1use core::marker::PhantomData;
2use core::marker::{PhantomData, PhantomPinned}; 2use core::mem::MaybeUninit;
3use core::pin::Pin;
4 3
5use cortex_m::peripheral::scb::VectActive; 4use cortex_m::peripheral::scb::VectActive;
6use cortex_m::peripheral::{NVIC, SCB}; 5use cortex_m::peripheral::{NVIC, SCB};
@@ -10,23 +9,23 @@ use embassy::interrupt::{Interrupt, InterruptExt};
10/// 9///
11/// It needs to be `Send` because `&mut` references are sent back and forth between the 'thread' which owns the `PeripheralMutex` and the interrupt, 10/// It needs to be `Send` because `&mut` references are sent back and forth between the 'thread' which owns the `PeripheralMutex` and the interrupt,
12/// and `&mut T` is only `Send` where `T: Send`. 11/// and `&mut T` is only `Send` where `T: Send`.
13///
14/// It also requires `'static` to be used safely with `PeripheralMutex::register_interrupt`,
15/// because although `Pin` guarantees that the memory of the state won't be invalidated,
16/// it doesn't guarantee that the lifetime will last.
17pub trait PeripheralState: Send { 12pub trait PeripheralState: Send {
18 type Interrupt: Interrupt; 13 type Interrupt: Interrupt;
19 fn on_interrupt(&mut self); 14 fn on_interrupt(&mut self);
20} 15}
21 16
22pub struct PeripheralMutex<S: PeripheralState> { 17pub struct StateStorage<S>(MaybeUninit<S>);
23 state: UnsafeCell<S>,
24 18
25 irq_setup_done: bool, 19impl<S> StateStorage<S> {
26 irq: S::Interrupt, 20 pub fn new() -> Self {
21 Self(MaybeUninit::uninit())
22 }
23}
27 24
28 _not_send: PhantomData<*mut ()>, 25pub struct PeripheralMutex<'a, S: PeripheralState> {
29 _pinned: PhantomPinned, 26 state: *mut S,
27 _phantom: PhantomData<&'a mut S>,
28 irq: S::Interrupt,
30} 29}
31 30
32/// Whether `irq` can be preempted by the current interrupt. 31/// Whether `irq` can be preempted by the current interrupt.
@@ -50,58 +49,45 @@ pub(crate) fn can_be_preempted(irq: &impl Interrupt) -> bool {
50 } 49 }
51} 50}
52 51
53impl<S: PeripheralState + 'static> PeripheralMutex<S> { 52impl<'a, S: PeripheralState> PeripheralMutex<'a, S> {
54 /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it. 53 /// Create a new `PeripheralMutex` wrapping `irq`, with the initial state `state`.
55 ///
56 /// This requires this `PeripheralMutex`'s `PeripheralState` to live for `'static`,
57 /// because `Pin` only guarantees that it's memory won't be repurposed,
58 /// not that it's lifetime will last.
59 /// 54 ///
60 /// To use non-`'static` `PeripheralState`, use the unsafe `register_interrupt_unchecked`. 55 /// self requires `state` to live for `'static`, because if the `PeripheralMutex` is leaked, the
56 /// interrupt won't be disabled, which may try accessing the state at any time. To use non-`'static`
57 /// state, see [`Self::new_unchecked`].
61 /// 58 ///
62 /// Note: `'static` doesn't mean it _has_ to live for the entire program, like an `&'static T`; 59 /// Registers `on_interrupt` as the `irq`'s handler, and enables it.
63 /// it just means it _can_ live for the entire program - for example, `u8` lives for `'static`. 60 pub fn new(storage: &'a mut StateStorage<S>, state: S, irq: S::Interrupt) -> Self
64 pub fn register_interrupt(self: Pin<&mut Self>) { 61 where
65 // SAFETY: `S: 'static`, so there's no way it's lifetime can expire. 62 'a: 'static,
66 unsafe { self.register_interrupt_unchecked() } 63 {
64 // safety: safe because state is `'static`.
65 unsafe { Self::new_unchecked(storage, state, irq) }
67 } 66 }
68}
69 67
70impl<S: PeripheralState> PeripheralMutex<S> { 68 /// Create a `PeripheralMutex` without requiring the state is `'static`.
71 /// Create a new `PeripheralMutex` wrapping `irq`, with the initial state `state`. 69 ///
72 pub fn new(state: S, irq: S::Interrupt) -> Self { 70 /// See also [`Self::new`].
71 ///
72 /// # Safety
73 /// The created instance must not be leaked (its `drop` must run).
74 pub unsafe fn new_unchecked(
75 storage: &'a mut StateStorage<S>,
76 state: S,
77 irq: S::Interrupt,
78 ) -> Self {
73 if can_be_preempted(&irq) { 79 if can_be_preempted(&irq) {
74 panic!("`PeripheralMutex` cannot be created in an interrupt with higher priority than the interrupt it wraps"); 80 panic!("`PeripheralMutex` cannot be created in an interrupt with higher priority than the interrupt it wraps");
75 } 81 }
76 82
77 Self { 83 let state_ptr = storage.0.as_mut_ptr();
78 irq,
79 irq_setup_done: false,
80 84
81 state: UnsafeCell::new(state), 85 // Safety: The pointer is valid and not used by anyone else
82 _not_send: PhantomData, 86 // because we have the `&mut StateStorage`.
83 _pinned: PhantomPinned, 87 state_ptr.write(state);
84 }
85 }
86
87 /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it.
88 ///
89 /// # Safety
90 /// The lifetime of any data in `PeripheralState` that is accessed by the interrupt handler
91 /// must not end without `Drop` being called on this `PeripheralMutex`.
92 ///
93 /// This can be accomplished by either not accessing any data with a lifetime in `on_interrupt`,
94 /// or making sure that nothing like `mem::forget` is used on the `PeripheralMutex`.
95
96 // TODO: this name isn't the best.
97 pub unsafe fn register_interrupt_unchecked(self: Pin<&mut Self>) {
98 let this = self.get_unchecked_mut();
99 if this.irq_setup_done {
100 return;
101 }
102 88
103 this.irq.disable(); 89 irq.disable();
104 this.irq.set_handler(|p| { 90 irq.set_handler(|p| {
105 // Safety: it's OK to get a &mut to the state, since 91 // Safety: it's OK to get a &mut to the state, since
106 // - We checked that the thread owning the `PeripheralMutex` can't preempt us in `new`. 92 // - We checked that the thread owning the `PeripheralMutex` can't preempt us in `new`.
107 // Interrupts' priorities can only be changed with raw embassy `Interrupts`, 93 // Interrupts' priorities can only be changed with raw embassy `Interrupts`,
@@ -110,23 +96,24 @@ impl<S: PeripheralState> PeripheralMutex<S> {
110 let state = unsafe { &mut *(p as *mut S) }; 96 let state = unsafe { &mut *(p as *mut S) };
111 state.on_interrupt(); 97 state.on_interrupt();
112 }); 98 });
113 this.irq 99 irq.set_handler_context(state_ptr as *mut ());
114 .set_handler_context((&mut this.state) as *mut _ as *mut ()); 100 irq.enable();
115 this.irq.enable();
116 101
117 this.irq_setup_done = true; 102 Self {
103 irq,
104 state: state_ptr,
105 _phantom: PhantomData,
106 }
118 } 107 }
119 108
120 pub fn with<R>(self: Pin<&mut Self>, f: impl FnOnce(&mut S) -> R) -> R { 109 pub fn with<R>(&mut self, f: impl FnOnce(&mut S) -> R) -> R {
121 let this = unsafe { self.get_unchecked_mut() }; 110 self.irq.disable();
122
123 this.irq.disable();
124 111
125 // Safety: it's OK to get a &mut to the state, since the irq is disabled. 112 // Safety: it's OK to get a &mut to the state, since the irq is disabled.
126 let state = unsafe { &mut *this.state.get() }; 113 let state = unsafe { &mut *self.state };
127 let r = f(state); 114 let r = f(state);
128 115
129 this.irq.enable(); 116 self.irq.enable();
130 117
131 r 118 r
132 } 119 }
@@ -152,9 +139,14 @@ impl<S: PeripheralState> PeripheralMutex<S> {
152 } 139 }
153} 140}
154 141
155impl<S: PeripheralState> Drop for PeripheralMutex<S> { 142impl<'a, S: PeripheralState> Drop for PeripheralMutex<'a, S> {
156 fn drop(&mut self) { 143 fn drop(&mut self) {
157 self.irq.disable(); 144 self.irq.disable();
158 self.irq.remove_handler(); 145 self.irq.remove_handler();
146
147 // safety:
148 // - we initialized the state in `new`, so we know it's initialized.
149 // - the irq is disabled, so it won't preempt us while dropping.
150 unsafe { self.state.drop_in_place() }
159 } 151 }
160} 152}
diff --git a/embassy-hal-common/src/usb/mod.rs b/embassy-hal-common/src/usb/mod.rs
index 1fb501d7f..0940e6b02 100644
--- a/embassy-hal-common/src/usb/mod.rs
+++ b/embassy-hal-common/src/usb/mod.rs
@@ -9,14 +9,31 @@ use usb_device::device::UsbDevice;
9mod cdc_acm; 9mod cdc_acm;
10pub mod usb_serial; 10pub mod usb_serial;
11 11
12use crate::peripheral::{PeripheralMutex, PeripheralState}; 12use crate::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
13use embassy::interrupt::Interrupt; 13use embassy::interrupt::Interrupt;
14use usb_serial::{ReadInterface, UsbSerial, WriteInterface}; 14use usb_serial::{ReadInterface, UsbSerial, WriteInterface};
15 15
16/// Marker trait to mark an interrupt to be used with the [`Usb`] abstraction. 16/// Marker trait to mark an interrupt to be used with the [`Usb`] abstraction.
17pub unsafe trait USBInterrupt: Interrupt + Send {} 17pub unsafe trait USBInterrupt: Interrupt + Send {}
18 18
19pub(crate) struct State<'bus, B, T, I> 19pub struct State<'bus, B, T, I>(StateStorage<StateInner<'bus, B, T, I>>)
20where
21 B: UsbBus,
22 T: ClassSet<B>,
23 I: USBInterrupt;
24
25impl<'bus, B, T, I> State<'bus, B, T, I>
26where
27 B: UsbBus,
28 T: ClassSet<B>,
29 I: USBInterrupt,
30{
31 pub fn new() -> Self {
32 Self(StateStorage::new())
33 }
34}
35
36pub(crate) struct StateInner<'bus, B, T, I>
20where 37where
21 B: UsbBus, 38 B: UsbBus,
22 T: ClassSet<B>, 39 T: ClassSet<B>,
@@ -34,7 +51,7 @@ where
34 I: USBInterrupt, 51 I: USBInterrupt,
35{ 52{
36 // Don't you dare moving out `PeripheralMutex` 53 // Don't you dare moving out `PeripheralMutex`
37 inner: RefCell<PeripheralMutex<State<'bus, B, T, I>>>, 54 inner: RefCell<PeripheralMutex<'bus, StateInner<'bus, B, T, I>>>,
38} 55}
39 56
40impl<'bus, B, T, I> Usb<'bus, B, T, I> 57impl<'bus, B, T, I> Usb<'bus, B, T, I>
@@ -43,30 +60,22 @@ where
43 T: ClassSet<B>, 60 T: ClassSet<B>,
44 I: USBInterrupt, 61 I: USBInterrupt,
45{ 62{
46 pub fn new<S: IntoClassSet<B, T>>(device: UsbDevice<'bus, B>, class_set: S, irq: I) -> Self { 63 pub fn new<S: IntoClassSet<B, T>>(
47 let state = State { 64 state: &'bus mut State<'bus, B, T, I>,
65 device: UsbDevice<'bus, B>,
66 class_set: S,
67 irq: I,
68 ) -> Self {
69 let initial_state = StateInner {
48 device, 70 device,
49 classes: class_set.into_class_set(), 71 classes: class_set.into_class_set(),
50 _interrupt: PhantomData, 72 _interrupt: PhantomData,
51 }; 73 };
52 let mutex = PeripheralMutex::new(state, irq); 74 let mutex = unsafe { PeripheralMutex::new_unchecked(&mut state.0, initial_state, irq) };
53 Self { 75 Self {
54 inner: RefCell::new(mutex), 76 inner: RefCell::new(mutex),
55 } 77 }
56 } 78 }
57
58 /// # Safety
59 /// The `UsbDevice` passed to `Self::new` must not be dropped without calling `Drop` on this `Usb` first.
60 pub unsafe fn start(self: Pin<&mut Self>) {
61 let this = self.get_unchecked_mut();
62 let mut mutex = this.inner.borrow_mut();
63 let mutex = Pin::new_unchecked(&mut *mutex);
64
65 // Use inner to register the irq
66 // SAFETY: the safety contract of this function makes sure the `UsbDevice` won't be invalidated
67 // without the `PeripheralMutex` being dropped.
68 mutex.register_interrupt_unchecked();
69 }
70} 79}
71 80
72impl<'bus, 'c, B, T, I> Usb<'bus, B, T, I> 81impl<'bus, 'c, B, T, I> Usb<'bus, B, T, I>
@@ -129,7 +138,7 @@ where
129 } 138 }
130} 139}
131 140
132impl<'bus, B, T, I> PeripheralState for State<'bus, B, T, I> 141impl<'bus, B, T, I> PeripheralState for StateInner<'bus, B, T, I>
133where 142where
134 B: UsbBus, 143 B: UsbBus,
135 T: ClassSet<B>, 144 T: ClassSet<B>,
diff --git a/embassy-hal-common/src/usb/usb_serial.rs b/embassy-hal-common/src/usb/usb_serial.rs
index a229b2000..8b27152b5 100644
--- a/embassy-hal-common/src/usb/usb_serial.rs
+++ b/embassy-hal-common/src/usb/usb_serial.rs
@@ -10,9 +10,10 @@ use usb_device::class_prelude::*;
10use usb_device::UsbError; 10use usb_device::UsbError;
11 11
12use super::cdc_acm::CdcAcmClass; 12use super::cdc_acm::CdcAcmClass;
13use super::StateInner;
13use crate::peripheral::PeripheralMutex; 14use crate::peripheral::PeripheralMutex;
14use crate::ring_buffer::RingBuffer; 15use crate::ring_buffer::RingBuffer;
15use crate::usb::{ClassSet, SerialState, State, USBInterrupt}; 16use crate::usb::{ClassSet, SerialState, USBInterrupt};
16 17
17pub struct ReadInterface<'a, 'bus, 'c, I, B, T, INT> 18pub struct ReadInterface<'a, 'bus, 'c, I, B, T, INT>
18where 19where
@@ -22,7 +23,7 @@ where
22 INT: USBInterrupt, 23 INT: USBInterrupt,
23{ 24{
24 // Don't you dare moving out `PeripheralMutex` 25 // Don't you dare moving out `PeripheralMutex`
25 pub(crate) inner: &'a RefCell<PeripheralMutex<State<'bus, B, T, INT>>>, 26 pub(crate) inner: &'a RefCell<PeripheralMutex<'bus, StateInner<'bus, B, T, INT>>>,
26 pub(crate) _buf_lifetime: PhantomData<&'c T>, 27 pub(crate) _buf_lifetime: PhantomData<&'c T>,
27 pub(crate) _index: PhantomData<I>, 28 pub(crate) _index: PhantomData<I>,
28} 29}
@@ -39,7 +40,7 @@ where
39 INT: USBInterrupt, 40 INT: USBInterrupt,
40{ 41{
41 // Don't you dare moving out `PeripheralMutex` 42 // Don't you dare moving out `PeripheralMutex`
42 pub(crate) inner: &'a RefCell<PeripheralMutex<State<'bus, B, T, INT>>>, 43 pub(crate) inner: &'a RefCell<PeripheralMutex<'bus, StateInner<'bus, B, T, INT>>>,
43 pub(crate) _buf_lifetime: PhantomData<&'c T>, 44 pub(crate) _buf_lifetime: PhantomData<&'c T>,
44 pub(crate) _index: PhantomData<I>, 45 pub(crate) _index: PhantomData<I>,
45} 46}
@@ -54,7 +55,6 @@ where
54 fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> { 55 fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
55 let this = self.get_mut(); 56 let this = self.get_mut();
56 let mut mutex = this.inner.borrow_mut(); 57 let mut mutex = this.inner.borrow_mut();
57 let mutex = unsafe { Pin::new_unchecked(&mut *mutex) };
58 mutex.with(|state| { 58 mutex.with(|state| {
59 let serial = state.classes.get_serial(); 59 let serial = state.classes.get_serial();
60 let serial = Pin::new(serial); 60 let serial = Pin::new(serial);
@@ -76,7 +76,6 @@ where
76 fn consume(self: Pin<&mut Self>, amt: usize) { 76 fn consume(self: Pin<&mut Self>, amt: usize) {
77 let this = self.get_mut(); 77 let this = self.get_mut();
78 let mut mutex = this.inner.borrow_mut(); 78 let mut mutex = this.inner.borrow_mut();
79 let mutex = unsafe { Pin::new_unchecked(&mut *mutex) };
80 mutex.with(|state| { 79 mutex.with(|state| {
81 let serial = state.classes.get_serial(); 80 let serial = state.classes.get_serial();
82 let serial = Pin::new(serial); 81 let serial = Pin::new(serial);
@@ -100,7 +99,6 @@ where
100 ) -> Poll<io::Result<usize>> { 99 ) -> Poll<io::Result<usize>> {
101 let this = self.get_mut(); 100 let this = self.get_mut();
102 let mut mutex = this.inner.borrow_mut(); 101 let mut mutex = this.inner.borrow_mut();
103 let mutex = unsafe { Pin::new_unchecked(&mut *mutex) };
104 mutex.with(|state| { 102 mutex.with(|state| {
105 let serial = state.classes.get_serial(); 103 let serial = state.classes.get_serial();
106 let serial = Pin::new(serial); 104 let serial = Pin::new(serial);