use core::marker::PhantomData;
pub unsafe trait RawMutex {
const INIT: Self;
fn lock<R>(&self, f: impl FnOnce() -> R) -> R;
}
#[derive(Debug)]
pub struct CriticalSectionRawMutex {
_phantom: PhantomData<()>,
}
unsafe impl Send for CriticalSectionRawMutex {}
unsafe impl Sync for CriticalSectionRawMutex {}
impl CriticalSectionRawMutex {
pub const fn new() -> Self {
Self { _phantom: PhantomData }
}
}
unsafe impl RawMutex for CriticalSectionRawMutex {
const INIT: Self = Self::new();
fn lock<R>(&self, f: impl FnOnce() -> R) -> R {
critical_section::with(|_| f())
}
}
#[derive(Debug)]
pub struct NoopRawMutex {
_phantom: PhantomData<*mut ()>,
}
unsafe impl Send for NoopRawMutex {}
impl NoopRawMutex {
pub const fn new() -> Self {
Self { _phantom: PhantomData }
}
}
unsafe impl RawMutex for NoopRawMutex {
const INIT: Self = Self::new();
fn lock<R>(&self, f: impl FnOnce() -> R) -> R {
f()
}
}
#[cfg(any(cortex_m, doc, feature = "std"))]
mod thread_mode {
use super::*;
pub struct ThreadModeRawMutex {
_phantom: PhantomData<()>,
}
unsafe impl Send for ThreadModeRawMutex {}
unsafe impl Sync for ThreadModeRawMutex {}
impl ThreadModeRawMutex {
pub const fn new() -> Self {
Self { _phantom: PhantomData }
}
}
unsafe impl RawMutex for ThreadModeRawMutex {
const INIT: Self = Self::new();
fn lock<R>(&self, f: impl FnOnce() -> R) -> R {
assert!(in_thread_mode(), "ThreadModeMutex can only be locked from thread mode.");
f()
}
}
impl Drop for ThreadModeRawMutex {
fn drop(&mut self) {
assert!(
in_thread_mode(),
"ThreadModeMutex can only be dropped from thread mode."
);
}
}
pub(crate) fn in_thread_mode() -> bool {
#[cfg(feature = "std")]
return Some("main") == std::thread::current().name();
#[cfg(not(feature = "std"))]
return unsafe { (0xE000ED04 as *const u32).read_volatile() } & 0x1FF == 0;
}
}
#[cfg(any(cortex_m, doc, feature = "std"))]
pub use thread_mode::*;