diff --git a/Cargo.toml b/Cargo.toml index 64b1162a..d93caca6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ links = "cortex-m" # prevent multiple versions of this crate to be linked toget [dependencies] bare-metal = { version = "0.2.0", features = ["const-fn"] } volatile-register = "0.2.0" +mutex-trait = "0.2.0" bitfield = "0.13.2" [features] diff --git a/src/lib.rs b/src/lib.rs index aedb95a5..6b280f04 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,5 +66,6 @@ pub mod interrupt; pub mod itm; pub mod peripheral; pub mod register; +pub mod mutex; pub use crate::peripheral::Peripherals; diff --git a/src/mutex.rs b/src/mutex.rs new file mode 100644 index 00000000..0975b83c --- /dev/null +++ b/src/mutex.rs @@ -0,0 +1,34 @@ +//! Implementation of a critical section based mutex that also implements the `mutex-trait`. +//! +//! ## Safety +//! +//! Note that this is only safe in single core applications. + +use core::cell::UnsafeCell; + +/// A critical section based mutex. +pub struct CriticalSectionMutex { + data: UnsafeCell, +} + +impl CriticalSectionMutex { + /// Create a new mutex + pub const fn new(data: T) -> Self { + CriticalSectionMutex { + data: UnsafeCell::new(data), + } + } +} + +impl mutex_trait::Mutex for &'_ CriticalSectionMutex { + type Data = T; + + fn lock(&mut self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + crate::interrupt::free(|_| f(unsafe { &mut *self.data.get() })) + } +} + +// NOTE A `Mutex` can be used as a channel so the protected data must be `Send` +// to prevent sending non-Sendable stuff (e.g. access tokens) across different +// execution contexts (e.g. interrupts) +unsafe impl Sync for CriticalSectionMutex where T: Send {}