use std::{
ops::{Deref, DerefMut},
panic::Location,
sync::Arc,
};
pub use crate::native::sync::mutex::NotAvailable;
use crate::{
flash::diag::{self, PrimEntry, PrimKind},
native::sync::mutex::{Mutex as NativeMutex, MutexGuard as NativeGuard},
};
pub struct Mutex<T> {
inner: NativeMutex<T>,
meta: Option<Arc<PrimEntry>>,
}
impl<T> Mutex<T> {
#[track_caller]
#[inline]
pub fn new(value: T) -> Self {
let meta = diag::register(PrimKind::Mutex, None, Location::caller());
Self {
inner: NativeMutex::new(value),
meta,
}
}
#[track_caller]
#[inline]
pub fn lock(&self) -> MutexGuard<'_, T> {
let at = Location::caller();
if let Some(m) = &self.meta {
m.enter_pending(at);
}
let inner = self.inner.lock();
if let Some(m) = &self.meta {
m.acquired(at);
}
MutexGuard {
inner,
meta: self.meta.as_deref(),
at,
}
}
#[track_caller]
#[inline]
pub fn try_lock(&self) -> Result<MutexGuard<'_, T>, NotAvailable> {
let at = Location::caller();
let inner = self.inner.try_lock()?;
if let Some(m) = &self.meta {
m.acquired(at);
}
Ok(MutexGuard {
inner,
meta: self.meta.as_deref(),
at,
})
}
}
impl<T: Default> Default for Mutex<T> {
fn default() -> Self {
Self::new(T::default())
}
}
pub struct MutexGuard<'a, T> {
inner: NativeGuard<'a, T>,
meta: Option<&'a PrimEntry>,
at: &'static Location<'static>,
}
impl<'a, T> MutexGuard<'a, T> {
#[inline]
pub fn unlocked<F: FnOnce()>(&mut self, f: F) {
if let Some(m) = self.meta {
m.released();
}
self.inner.unlocked(f);
if let Some(m) = self.meta {
m.acquired(self.at);
}
}
#[inline]
pub(in crate::flash) fn native_mut(&mut self) -> &mut NativeGuard<'a, T> {
&mut self.inner
}
#[inline]
pub(in crate::flash) fn meta(&self) -> Option<&'a PrimEntry> {
self.meta
}
#[inline]
pub(in crate::flash) fn site(&self) -> &'static Location<'static> {
self.at
}
}
impl<T> Drop for MutexGuard<'_, T> {
#[inline]
fn drop(&mut self) {
if let Some(m) = self.meta {
m.released();
}
}
}
impl<T> Deref for MutexGuard<'_, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
&self.inner
}
}
impl<T> DerefMut for MutexGuard<'_, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
&mut self.inner
}
}