aboutsummaryrefslogtreecommitdiff
path: root/embassy-extras
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-03-18 02:01:29 +0100
committerDario Nieuwenhuis <[email protected]>2021-03-18 18:49:10 +0100
commit0cd19a58c3dcaa689ba57da80c02af75866f7e09 (patch)
treefc27bb5c7dad30e401aa0ef9df28be9e3aacc1f5 /embassy-extras
parent4b2fdd450e70270f346f302829fa493a67fe3ce1 (diff)
Remove free() from PeripheralMutex and all nrf drivers.
Diffstat (limited to 'embassy-extras')
-rw-r--r--embassy-extras/src/peripheral.rs77
1 files changed, 20 insertions, 57 deletions
diff --git a/embassy-extras/src/peripheral.rs b/embassy-extras/src/peripheral.rs
index e9357969d..aa23bc978 100644
--- a/embassy-extras/src/peripheral.rs
+++ b/embassy-extras/src/peripheral.rs
@@ -1,30 +1,20 @@
1use core::cell::UnsafeCell; 1use core::cell::UnsafeCell;
2use core::marker::{PhantomData, PhantomPinned}; 2use core::marker::{PhantomData, PhantomPinned};
3use core::mem::MaybeUninit;
4use core::pin::Pin; 3use core::pin::Pin;
5use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{compiler_fence, Ordering};
6 5
7use embassy::interrupt::{Interrupt, InterruptExt}; 6use embassy::interrupt::{Interrupt, InterruptExt};
8 7
9use crate::fmt::assert;
10
11pub trait PeripheralState { 8pub trait PeripheralState {
12 type Interrupt: Interrupt; 9 type Interrupt: Interrupt;
13 fn on_interrupt(&mut self); 10 fn on_interrupt(&mut self);
14} 11}
15 12
16#[derive(Clone, Copy, PartialEq, Eq, Debug)]
17enum Life {
18 Ready,
19 Created,
20 Freed,
21}
22
23pub struct PeripheralMutex<S: PeripheralState> { 13pub struct PeripheralMutex<S: PeripheralState> {
24 life: Life, 14 state: UnsafeCell<S>,
25 15
26 state: MaybeUninit<UnsafeCell<S>>, // Init if life != Freed 16 irq_setup_done: bool,
27 irq: MaybeUninit<S::Interrupt>, // Init if life != Freed 17 irq: S::Interrupt,
28 18
29 _not_send: PhantomData<*mut ()>, 19 _not_send: PhantomData<*mut ()>,
30 _pinned: PhantomPinned, 20 _pinned: PhantomPinned,
@@ -33,9 +23,10 @@ pub struct PeripheralMutex<S: PeripheralState> {
33impl<S: PeripheralState> PeripheralMutex<S> { 23impl<S: PeripheralState> PeripheralMutex<S> {
34 pub fn new(state: S, irq: S::Interrupt) -> Self { 24 pub fn new(state: S, irq: S::Interrupt) -> Self {
35 Self { 25 Self {
36 life: Life::Created, 26 irq,
37 state: MaybeUninit::new(UnsafeCell::new(state)), 27 irq_setup_done: false,
38 irq: MaybeUninit::new(irq), 28
29 state: UnsafeCell::new(state),
39 _not_send: PhantomData, 30 _not_send: PhantomData,
40 _pinned: PhantomPinned, 31 _pinned: PhantomPinned,
41 } 32 }
@@ -43,77 +34,49 @@ impl<S: PeripheralState> PeripheralMutex<S> {
43 34
44 /// safety: self must be pinned. 35 /// safety: self must be pinned.
45 unsafe fn setup(&mut self) { 36 unsafe fn setup(&mut self) {
46 assert!(self.life == Life::Created); 37 self.irq.disable();
47
48 let irq = &mut *self.irq.as_mut_ptr();
49 irq.disable();
50 compiler_fence(Ordering::SeqCst); 38 compiler_fence(Ordering::SeqCst);
51 39
52 irq.set_handler(|p| { 40 self.irq.set_handler(|p| {
53 // Safety: it's OK to get a &mut to the state, since 41 // Safety: it's OK to get a &mut to the state, since
54 // - We're in the IRQ, no one else can't preempt us 42 // - We're in the IRQ, no one else can't preempt us
55 // - We can't have preempted a with() call because the irq is disabled during it. 43 // - We can't have preempted a with() call because the irq is disabled during it.
56 let state = &mut *(p as *mut S); 44 let state = &mut *(p as *mut S);
57 state.on_interrupt(); 45 state.on_interrupt();
58 }); 46 });
59 irq.set_handler_context(self.state.as_mut_ptr() as *mut ()); 47 self.irq
48 .set_handler_context((&mut self.state) as *mut _ as *mut ());
60 49
61 compiler_fence(Ordering::SeqCst); 50 compiler_fence(Ordering::SeqCst);
62 irq.enable(); 51 self.irq.enable();
63 52
64 self.life = Life::Ready; 53 self.irq_setup_done = true;
65 } 54 }
66 55
67 pub fn with<R>(self: Pin<&mut Self>, f: impl FnOnce(&mut S, &mut S::Interrupt) -> R) -> R { 56 pub fn with<R>(self: Pin<&mut Self>, f: impl FnOnce(&mut S, &mut S::Interrupt) -> R) -> R {
68 let this = unsafe { self.get_unchecked_mut() }; 57 let this = unsafe { self.get_unchecked_mut() };
69 if this.life != Life::Ready { 58 if !this.irq_setup_done {
70 unsafe { this.setup() } 59 unsafe { this.setup() }
71 } 60 }
72 61
73 let irq = unsafe { &mut *this.irq.as_mut_ptr() }; 62 this.irq.disable();
74
75 irq.disable();
76 compiler_fence(Ordering::SeqCst); 63 compiler_fence(Ordering::SeqCst);
77 64
78 // Safety: it's OK to get a &mut to the state, since the irq is disabled. 65 // Safety: it's OK to get a &mut to the state, since the irq is disabled.
79 let state = unsafe { &mut *(*this.state.as_ptr()).get() }; 66 let state = unsafe { &mut *this.state.get() };
80 67
81 let r = f(state, irq); 68 let r = f(state, &mut this.irq);
82 69
83 compiler_fence(Ordering::SeqCst); 70 compiler_fence(Ordering::SeqCst);
84 irq.enable(); 71 this.irq.enable();
85 72
86 r 73 r
87 } 74 }
88
89 pub fn try_free(self: Pin<&mut Self>) -> Option<(S, S::Interrupt)> {
90 let this = unsafe { self.get_unchecked_mut() };
91
92 if this.life != Life::Freed {
93 return None;
94 }
95
96 unsafe { &mut *this.irq.as_mut_ptr() }.disable();
97 compiler_fence(Ordering::SeqCst);
98
99 this.life = Life::Freed;
100
101 let state = unsafe { this.state.as_ptr().read().into_inner() };
102 let irq = unsafe { this.irq.as_ptr().read() };
103 Some((state, irq))
104 }
105
106 pub fn free(self: Pin<&mut Self>) -> (S, S::Interrupt) {
107 unwrap!(self.try_free())
108 }
109} 75}
110 76
111impl<S: PeripheralState> Drop for PeripheralMutex<S> { 77impl<S: PeripheralState> Drop for PeripheralMutex<S> {
112 fn drop(&mut self) { 78 fn drop(&mut self) {
113 if self.life != Life::Freed { 79 self.irq.disable();
114 let irq = unsafe { &mut *self.irq.as_mut_ptr() }; 80 self.irq.remove_handler();
115 irq.disable();
116 irq.remove_handler();
117 }
118 } 81 }
119} 82}