use core::{ cell::UnsafeCell, ops::{Deref, DerefMut}, }; use super::{ semaphore::{RwSemaphoreStrategy, SemaphoreStrategy}, spin::IrqStrategy, strategy::LockStrategy, RwSemWriteGuard, SemGuard, }; pub struct Lock { strategy_data: Strategy::StrategyData, value: UnsafeCell, } unsafe impl Send for Lock {} unsafe impl Sync for Lock {} impl Lock { #[inline(always)] pub fn new(value: Value) -> Self { Self { strategy_data: Strategy::data(), value: UnsafeCell::new(value), } } } impl core::fmt::Debug for Lock { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("Lock") .field("locked_value", &self.value) .finish() } } impl Clone for Lock { fn clone(&self) -> Self { Self { strategy_data: Strategy::data(), value: UnsafeCell::new(self.lock_shared().clone()), } } } impl Default for Lock { fn default() -> Self { Self { strategy_data: Strategy::data(), value: Default::default(), } } } #[allow(dead_code)] impl Lock { #[inline(always)] pub fn lock_nosleep(&self) -> SemGuard<'_, Value> { loop { if !self.is_locked() { if let Some(guard) = self.try_lock() { return guard; } } arch::pause(); } } } impl Lock { #[inline(always)] pub fn lock_nosleep(&self) -> RwSemWriteGuard<'_, Value> { loop { if self.is_locked() { if let Some(guard) = self.try_lock() { return guard; } } arch::pause(); } } } #[allow(dead_code)] impl Lock { #[inline(always)] pub fn is_locked(&self) -> bool { unsafe { Strategy::is_locked(&self.strategy_data) } } #[inline(always)] pub fn try_lock<'lt>(&'lt self) -> Option> { if unsafe { Strategy::is_locked(&self.strategy_data) } { return None; } unsafe { Strategy::try_lock(&self.strategy_data) }.map(|context| Guard { _phantom: core::marker::PhantomData, value: &self.value, strategy_data: &self.strategy_data, context, }) } #[inline(always)] pub fn lock<'lt>(&'lt self) -> Guard<'lt, Value, Strategy> { Guard { _phantom: core::marker::PhantomData, value: &self.value, strategy_data: &self.strategy_data, context: unsafe { Strategy::do_lock(&self.strategy_data) }, } } #[inline(always)] pub fn lock_irq<'lt>(&'lt self) -> Guard<'lt, Value, IrqStrategy> { Guard { _phantom: core::marker::PhantomData, value: &self.value, strategy_data: &self.strategy_data, context: unsafe { IrqStrategy::::do_lock(&self.strategy_data) }, } } #[inline(always)] pub fn lock_shared<'lt>(&'lt self) -> Guard<'lt, Value, Strategy, false> { Guard { _phantom: core::marker::PhantomData, value: &self.value, strategy_data: &self.strategy_data, context: unsafe { Strategy::do_lock_shared(&self.strategy_data) }, } } #[inline(always)] pub fn lock_shared_irq<'lt>(&'lt self) -> Guard<'lt, Value, IrqStrategy, false> { Guard { _phantom: core::marker::PhantomData, value: &self.value, strategy_data: &self.strategy_data, context: unsafe { IrqStrategy::::do_lock(&self.strategy_data) }, } } #[inline(always)] pub fn get_mut(&mut self) -> &mut Value { unsafe { &mut *self.value.get() } } } pub struct Guard<'lock, Value: ?Sized, Strategy: LockStrategy, const WRITE: bool = true> { _phantom: core::marker::PhantomData, value: &'lock UnsafeCell, strategy_data: &'lock Strategy::StrategyData, context: Strategy::GuardContext, } impl<'lock, Value: ?Sized, Strategy: LockStrategy, const W: bool> Guard<'lock, Value, Strategy, W> { /// # Safety /// Use of the lock after calling this function without relocking is undefined behavior. #[inline(always)] pub unsafe fn force_unlock(&mut self) { Strategy::do_temporary_unlock(&self.strategy_data, &mut self.context) } /// # Safety /// Calling this function more than once will cause deadlocks. #[inline(always)] pub unsafe fn force_relock(&mut self) { Strategy::do_relock(&self.strategy_data, &mut self.context) } } impl<'lock, Value: ?Sized, Strategy: LockStrategy, const WRITE: bool> Deref for Guard<'lock, Value, Strategy, WRITE> { type Target = Value; fn deref(&self) -> &Self::Target { unsafe { &*self.value.get() } } } impl<'lock, Value: ?Sized, Strategy: LockStrategy> DerefMut for Guard<'lock, Value, Strategy, true> { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { &mut *self.value.get() } } } impl<'lock, Value: ?Sized, Strategy: LockStrategy, const WRITE: bool> AsRef for Guard<'lock, Value, Strategy, WRITE> { fn as_ref(&self) -> &Value { unsafe { &*self.value.get() } } } impl<'lock, Value: ?Sized, Strategy: LockStrategy> AsMut for Guard<'lock, Value, Strategy, true> { fn as_mut(&mut self) -> &mut Value { unsafe { &mut *self.value.get() } } } impl<'lock, Value: ?Sized, Strategy: LockStrategy, const WRITE: bool> Drop for Guard<'lock, Value, Strategy, WRITE> { fn drop(&mut self) { unsafe { Strategy::do_unlock(&self.strategy_data, &mut self.context) } } }