use core::{cell::UnsafeCell, fmt, marker::PhantomData};
use crate::{
hunk::{CfgHunkBuilder, DefaultInitTag, Hunk, HunkIniter},
kernel::{
self,
cfg::{CfgBuilder, CfgMutexBuilder},
LockMutexError, MarkConsistentMutexError, MutexProtocol, TryLockMutexError,
},
prelude::*,
};
pub struct Builder<System, T, InitTag> {
mutex: CfgMutexBuilder<System>,
hunk: CfgHunkBuilder<System, UnsafeCell<T>, InitTag>,
}
pub struct Mutex<System, T> {
hunk: Hunk<System, UnsafeCell<T>>,
mutex: kernel::Mutex<System>,
}
unsafe impl<System: Kernel, T: 'static + Send> Send for Mutex<System, T> {}
unsafe impl<System: Kernel, T: 'static + Send> Sync for Mutex<System, T> {}
#[must_use = "if unused the Mutex will immediately unlock"]
pub struct MutexGuard<'a, System: Kernel, T: 'static> {
mutex: &'a Mutex<System, T>,
_no_send_sync: PhantomData<*mut ()>,
}
unsafe impl<System: Kernel, T: 'static + Sync> Sync for MutexGuard<'_, System, T> {}
pub type LockResult<Guard> = Result<Guard, LockError<Guard>>;
pub type TryLockResult<Guard> = Result<Guard, TryLockError<Guard>>;
#[repr(i8)]
pub enum LockError<Guard> {
BadContext = LockMutexError::BadContext as i8,
Interrupted = LockMutexError::Interrupted as i8,
WouldDeadlock = LockMutexError::WouldDeadlock as i8,
BadParam = LockMutexError::BadParam as i8,
Abandoned(Guard) = LockMutexError::Abandoned as i8,
}
impl<Guard> fmt::Debug for LockError<Guard> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Self::BadContext => "BadContext",
Self::Interrupted => "Interrupted",
Self::WouldDeadlock => "WouldDeadlock",
Self::BadParam => "BadParam",
Self::Abandoned(_) => "Abandoned",
})
}
}
#[repr(i8)]
pub enum TryLockError<Guard> {
BadContext = TryLockMutexError::BadContext as i8,
WouldDeadlock = LockMutexError::WouldDeadlock as i8,
WouldBlock = TryLockMutexError::Timeout as i8,
BadParam = TryLockMutexError::BadParam as i8,
Abandoned(Guard) = TryLockMutexError::Abandoned as i8,
}
impl<Guard> fmt::Debug for TryLockError<Guard> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Self::BadContext => "BadContext",
Self::WouldBlock => "WouldBlock",
Self::WouldDeadlock => "WouldDeadlock",
Self::BadParam => "BadParam",
Self::Abandoned(_) => "Abandoned",
})
}
}
#[derive(Debug)]
#[repr(i8)]
pub enum MarkConsistentError {
BadContext = MarkConsistentMutexError::BadContext as i8,
Consistent = MarkConsistentMutexError::BadObjectState as i8,
}
impl<System: Kernel, T: 'static> Mutex<System, T> {
pub const fn build() -> Builder<System, T, DefaultInitTag> {
Builder {
mutex: kernel::Mutex::build(),
hunk: Hunk::build(),
}
}
}
impl<System: Kernel, T: 'static, InitTag> Builder<System, T, InitTag> {
pub const fn protocol(self, protocol: MutexProtocol) -> Self {
Self {
mutex: self.mutex.protocol(protocol),
..self
}
}
}
impl<System: Kernel, T: 'static, InitTag: HunkIniter<UnsafeCell<T>>> Builder<System, T, InitTag> {
pub const fn finish(self, cfg: &mut CfgBuilder<System>) -> Mutex<System, T> {
Mutex {
hunk: self.hunk.finish(cfg),
mutex: self.mutex.finish(cfg),
}
}
}
impl<System: Kernel, T: 'static> Mutex<System, T> {
pub fn lock(&self) -> LockResult<MutexGuard<'_, System, T>> {
match self.mutex.lock() {
Ok(()) => Ok(MutexGuard {
mutex: self,
_no_send_sync: PhantomData,
}),
Err(LockMutexError::BadId) => unreachable!(),
Err(LockMutexError::BadContext) => Err(LockError::BadContext),
Err(LockMutexError::Interrupted) => Err(LockError::Interrupted),
Err(LockMutexError::WouldDeadlock) => Err(LockError::WouldDeadlock),
Err(LockMutexError::BadParam) => Err(LockError::BadParam),
Err(LockMutexError::Abandoned) => Err(LockError::Abandoned(MutexGuard {
mutex: self,
_no_send_sync: PhantomData,
})),
}
}
pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, System, T>> {
match self.mutex.try_lock() {
Ok(()) => Ok(MutexGuard {
mutex: self,
_no_send_sync: PhantomData,
}),
Err(TryLockMutexError::BadId) => unreachable!(),
Err(TryLockMutexError::BadContext) => Err(TryLockError::BadContext),
Err(TryLockMutexError::WouldDeadlock) => Err(TryLockError::WouldDeadlock),
Err(TryLockMutexError::Timeout) => Err(TryLockError::WouldBlock),
Err(TryLockMutexError::BadParam) => Err(TryLockError::BadParam),
Err(TryLockMutexError::Abandoned) => Err(TryLockError::Abandoned(MutexGuard {
mutex: self,
_no_send_sync: PhantomData,
})),
}
}
pub fn mark_consistent(&self) -> Result<(), MarkConsistentError> {
self.mutex.mark_consistent().map_err(|e| match e {
MarkConsistentMutexError::BadId => unreachable!(),
MarkConsistentMutexError::BadContext => MarkConsistentError::BadContext,
MarkConsistentMutexError::BadObjectState => MarkConsistentError::Consistent,
})
}
#[inline]
pub fn get_ptr(&self) -> *mut T {
self.hunk.get()
}
}
impl<System: Kernel, T: fmt::Debug + 'static> fmt::Debug for Mutex<System, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.try_lock() {
Ok(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(),
Err(TryLockError::BadContext) => {
struct BadContextPlaceholder;
impl fmt::Debug for BadContextPlaceholder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("<CPU context active>")
}
}
f.debug_struct("Mutex")
.field("data", &BadContextPlaceholder)
.finish()
}
Err(TryLockError::WouldBlock | TryLockError::WouldDeadlock) => {
struct LockedPlaceholder;
impl fmt::Debug for LockedPlaceholder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("<locked>")
}
}
f.debug_struct("Mutex")
.field("data", &LockedPlaceholder)
.finish()
}
Err(TryLockError::Abandoned(_)) => {
struct AbandonedPlaceholder;
impl fmt::Debug for AbandonedPlaceholder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("<abandoned>")
}
}
f.debug_struct("Mutex")
.field("data", &AbandonedPlaceholder)
.finish()
}
Err(TryLockError::BadParam) => {
struct BadParamPlaceholder;
impl fmt::Debug for BadParamPlaceholder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("<current priority too high>")
}
}
f.debug_struct("Mutex")
.field("data", &BadParamPlaceholder)
.finish()
}
}
}
}
impl<System: Kernel, T: fmt::Debug + 'static> fmt::Debug for MutexGuard<'_, System, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<System: Kernel, T: fmt::Display + 'static> fmt::Display for MutexGuard<'_, System, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
impl<System: Kernel, T: 'static> Drop for MutexGuard<'_, System, T> {
#[inline]
fn drop(&mut self) {
self.mutex.mutex.unlock().unwrap();
}
}
impl<System: Kernel, T: 'static> core::ops::Deref for MutexGuard<'_, System, T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { &*self.mutex.hunk.get() }
}
}
impl<System: Kernel, T: 'static> core::ops::DerefMut for MutexGuard<'_, System, T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.mutex.hunk.get() }
}
}