diff --git a/embassy/src/util/critical_section.rs b/embassy/src/util/critical_section.rs new file mode 100644 index 00000000..12ad6f20 --- /dev/null +++ b/embassy/src/util/critical_section.rs @@ -0,0 +1,30 @@ +pub use cs::{critical_section, CriticalSection}; + +#[cfg(feature = "std")] +mod cs { + static INIT: std::sync::Once = std::sync::Once::new(); + static mut BKL: Option> = None; + + pub type CriticalSection = std::sync::MutexGuard<'static, ()>; + pub fn critical_section(f: F) -> R + where + F: FnOnce(&CriticalSection) -> R, + { + INIT.call_once(|| unsafe { + BKL.replace(std::sync::Mutex::new(())); + }); + let guard = unsafe { BKL.as_ref().unwrap().lock().unwrap() }; + f(&guard) + } +} + +#[cfg(not(feature = "std"))] +mod cs { + pub use cortex_m::interrupt::CriticalSection; + pub fn critical_section(f: F) -> R + where + F: FnOnce(&CriticalSection) -> R, + { + cortex_m::interrupt::free(f) + } +} diff --git a/embassy/src/util/mod.rs b/embassy/src/util/mod.rs index 9f82422d..25b570cc 100644 --- a/embassy/src/util/mod.rs +++ b/embassy/src/util/mod.rs @@ -5,6 +5,7 @@ mod mutex; mod on_drop; mod portal; mod signal; +mod critical_section; #[cfg_attr(feature = "executor-agnostic", path = "waker_agnostic.rs")] mod waker; @@ -16,6 +17,7 @@ pub use on_drop::*; pub use portal::*; pub use signal::*; pub use waker::*; +pub use critical_section::*; pub trait PeripheralBorrow { type Target; diff --git a/embassy/src/util/signal.rs b/embassy/src/util/signal.rs index 2fc86906..a62abcd5 100644 --- a/embassy/src/util/signal.rs +++ b/embassy/src/util/signal.rs @@ -11,6 +11,7 @@ use ptr::NonNull; use crate::executor; use crate::fmt::panic; use crate::interrupt::{Interrupt, InterruptExt}; +use crate::util::critical_section::critical_section; /// Synchronization primitive. Allows creating awaitable signals that may be passed between tasks. /// @@ -37,7 +38,7 @@ impl Signal { /// Mark this Signal as completed. pub fn signal(&self, val: T) { - cortex_m::interrupt::free(|_| unsafe { + critical_section(|_| unsafe { let state = &mut *self.state.get(); if let State::Waiting(waker) = mem::replace(state, State::Signaled(val)) { waker.wake(); @@ -46,14 +47,14 @@ impl Signal { } pub fn reset(&self) { - cortex_m::interrupt::free(|_| unsafe { + critical_section(|_| unsafe { let state = &mut *self.state.get(); *state = State::None }) } pub fn poll_wait(&self, cx: &mut Context<'_>) -> Poll { - cortex_m::interrupt::free(|_| unsafe { + critical_section(|_| unsafe { let state = &mut *self.state.get(); match state { State::None => { @@ -77,7 +78,7 @@ impl Signal { /// non-blocking method to check whether this signal has been signaled. pub fn signaled(&self) -> bool { - cortex_m::interrupt::free(|_| matches!(unsafe { &*self.state.get() }, State::Signaled(_))) + critical_section(|_| matches!(unsafe { &*self.state.get() }, State::Signaled(_))) } }