diff --git a/embassy/src/util/mod.rs b/embassy/src/util/mod.rs index 5694d6bf..ae434a8b 100644 --- a/embassy/src/util/mod.rs +++ b/embassy/src/util/mod.rs @@ -1,11 +1,13 @@ mod drop_bomb; mod forever; +mod mutex; mod portal; mod signal; mod waker; pub use drop_bomb::*; pub use forever::*; +pub use mutex::*; pub use portal::*; pub use signal::*; pub use waker::*; diff --git a/embassy/src/util/mutex.rs b/embassy/src/util/mutex.rs new file mode 100644 index 00000000..11f88049 --- /dev/null +++ b/embassy/src/util/mutex.rs @@ -0,0 +1,75 @@ +use core::cell::UnsafeCell; +use cortex_m::interrupt::CriticalSection; + +use crate::fmt::{assert, panic, *}; + +/// A "mutex" based on critical sections +/// +/// # Safety +/// +/// **This Mutex is only safe on single-core systems.** +/// +/// On multi-core systems, a `CriticalSection` **is not sufficient** to ensure exclusive access. +pub struct CriticalSectionMutex { + inner: UnsafeCell, +} +unsafe impl Sync for CriticalSectionMutex {} +unsafe impl Send for CriticalSectionMutex {} + +impl CriticalSectionMutex { + /// Creates a new mutex + pub const fn new(value: T) -> Self { + CriticalSectionMutex { + inner: UnsafeCell::new(value), + } + } +} + +impl CriticalSectionMutex { + /// Borrows the data for the duration of the critical section + pub fn borrow<'cs>(&'cs self, _cs: &'cs CriticalSection) -> &'cs T { + unsafe { &*self.inner.get() } + } +} + +/// A "mutex" that only allows borrowing from thread mode. +/// +/// # Safety +/// +/// **This Mutex is only safe on single-core systems.** +/// +/// On multi-core systems, a `ThreadModeMutex` **is not sufficient** to ensure exclusive access. +pub struct ThreadModeMutex { + inner: UnsafeCell, +} +unsafe impl Sync for ThreadModeMutex {} +unsafe impl Send for ThreadModeMutex {} + +impl ThreadModeMutex { + /// Creates a new mutex + pub const fn new(value: T) -> Self { + ThreadModeMutex { + inner: UnsafeCell::new(value), + } + } +} + +impl ThreadModeMutex { + /// Borrows the data + pub fn borrow(&self) -> &T { + assert!( + in_thread_mode(), + "ThreadModeMutex can only be borrowed from thread mode." + ); + unsafe { &*self.inner.get() } + } +} + +pub fn in_thread_mode() -> bool { + #[cfg(feature = "std")] + return Some("main") == std::thread::current().name(); + + #[cfg(not(feature = "std"))] + return cortex_m::peripheral::SCB::vect_active() + == cortex_m::peripheral::scb::VectActive::ThreadMode; +}