aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-executor/src/raw/run_queue.rs21
1 files changed, 17 insertions, 4 deletions
diff --git a/embassy-executor/src/raw/run_queue.rs b/embassy-executor/src/raw/run_queue.rs
index 9acb9dd28..97d26a18a 100644
--- a/embassy-executor/src/raw/run_queue.rs
+++ b/embassy-executor/src/raw/run_queue.rs
@@ -157,19 +157,26 @@ fn run_dequeue(taskref: &TaskRef) {
157/// A wrapper type that acts like TransferStack by wrapping a normal Stack in a CS mutex 157/// A wrapper type that acts like TransferStack by wrapping a normal Stack in a CS mutex
158#[cfg(not(target_has_atomic = "ptr"))] 158#[cfg(not(target_has_atomic = "ptr"))]
159struct MutexTransferStack<T: Linked<cordyceps::stack::Links<T>>> { 159struct MutexTransferStack<T: Linked<cordyceps::stack::Links<T>>> {
160 inner: critical_section::Mutex<core::cell::RefCell<cordyceps::Stack<T>>>, 160 inner: critical_section::Mutex<core::cell::UnsafeCell<cordyceps::Stack<T>>>,
161} 161}
162 162
163#[cfg(not(target_has_atomic = "ptr"))] 163#[cfg(not(target_has_atomic = "ptr"))]
164impl<T: Linked<cordyceps::stack::Links<T>>> MutexTransferStack<T> { 164impl<T: Linked<cordyceps::stack::Links<T>>> MutexTransferStack<T> {
165 const fn new() -> Self { 165 const fn new() -> Self {
166 Self { 166 Self {
167 inner: critical_section::Mutex::new(core::cell::RefCell::new(cordyceps::Stack::new())), 167 inner: critical_section::Mutex::new(core::cell::UnsafeCell::new(cordyceps::Stack::new())),
168 } 168 }
169 } 169 }
170 170
171 /// Push an item to the transfer stack, returning whether the stack was previously empty
171 fn push_was_empty(&self, item: T::Handle, token: super::state::Token) -> bool { 172 fn push_was_empty(&self, item: T::Handle, token: super::state::Token) -> bool {
172 let mut guard = self.inner.borrow_ref_mut(token); 173 /// SAFETY: The critical-section mutex guarantees that there is no *concurrent* access
174 /// for the lifetime of the token, but does NOT protect against re-entrant access.
175 /// However, we never *return* the reference, nor do we recurse (or call another method
176 /// like `take_all`) that could ever allow for re-entrant aliasing. Therefore, the
177 /// presence of the critical section is sufficient to guarantee exclusive access to
178 /// the `inner` field for the purposes of this function
179 let mut guard = unsafe { &mut *self.inner.borrow(token).get() };
173 let is_empty = guard.is_empty(); 180 let is_empty = guard.is_empty();
174 guard.push(item); 181 guard.push(item);
175 is_empty 182 is_empty
@@ -177,7 +184,13 @@ impl<T: Linked<cordyceps::stack::Links<T>>> MutexTransferStack<T> {
177 184
178 fn take_all(&self) -> cordyceps::Stack<T> { 185 fn take_all(&self) -> cordyceps::Stack<T> {
179 critical_section::with(|cs| { 186 critical_section::with(|cs| {
180 let mut guard = self.inner.borrow_ref_mut(cs); 187 /// SAFETY: The critical-section mutex guarantees that there is no *concurrent* access
188 /// for the lifetime of the token, but does NOT protect against re-entrant access.
189 /// However, we never *return* the reference, nor do we recurse (or call another method
190 /// like `push_was_empty`) that could ever allow for re-entrant aliasing. Therefore, the
191 /// presence of the critical section is sufficient to guarantee exclusive access to
192 /// the `inner` field for the purposes of this function
193 let mut guard = unsafe { &mut *self.inner.borrow(cs).get() };
181 guard.take_all() 194 guard.take_all()
182 }) 195 })
183 } 196 }