#[cfg(feature = "smp")]
use core::sync::atomic::{AtomicBool, Ordering};
use core::{cell::UnsafeCell, marker::PhantomData};
use crate::sync::context::{GuardState, PreemptIrqSaveState};
struct BaseRawSpinLock<G: GuardState> {
_phantom: PhantomData<G>,
#[cfg(feature = "smp")]
locked: AtomicBool,
state: UnsafeCell<Option<G::State>>,
}
unsafe impl<G: GuardState> Sync for BaseRawSpinLock<G> {}
impl<G: GuardState> BaseRawSpinLock<G> {
pub const fn new() -> Self {
Self {
_phantom: PhantomData,
#[cfg(feature = "smp")]
locked: AtomicBool::new(false),
state: UnsafeCell::new(None),
}
}
#[inline]
fn save_state(&self, state: G::State) {
unsafe {
*self.state.get() = Some(state);
}
}
#[inline]
fn take_state(&self) -> G::State {
unsafe {
(*self.state.get())
.take()
.expect("raw spinlock unlocked without saved guard state")
}
}
}
impl<G: GuardState> Default for BaseRawSpinLock<G> {
fn default() -> Self {
Self::new()
}
}
unsafe impl<G: GuardState + Send + Sync + 'static> lock_api::RawMutex for BaseRawSpinLock<G> {
const INIT: Self = Self::new();
type GuardMarker = lock_api::GuardNoSend;
fn lock(&self) {
let state = G::acquire();
#[cfg(feature = "smp")]
{
while self
.locked
.compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_err()
{
while self.locked.load(Ordering::Acquire) {
core::hint::spin_loop();
}
}
}
self.save_state(state);
}
fn try_lock(&self) -> bool {
let state = G::acquire();
#[cfg(feature = "smp")]
{
if self
.locked
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_err()
{
G::release(state);
return false;
}
}
self.save_state(state);
true
}
unsafe fn unlock(&self) {
let state = self.take_state();
#[cfg(feature = "smp")]
self.locked.store(false, Ordering::Release);
G::release(state);
}
}
#[repr(transparent)]
pub struct RawIrqSaveMutex(BaseRawSpinLock<PreemptIrqSaveState>);
impl RawIrqSaveMutex {
pub const fn new() -> Self {
Self(BaseRawSpinLock::new())
}
}
impl Default for RawIrqSaveMutex {
fn default() -> Self {
Self::new()
}
}
unsafe impl lock_api::RawMutex for RawIrqSaveMutex {
const INIT: Self = Self::new();
type GuardMarker = lock_api::GuardNoSend;
#[inline]
fn lock(&self) {
self.0.lock();
}
#[inline]
fn try_lock(&self) -> bool {
self.0.try_lock()
}
#[inline]
unsafe fn unlock(&self) {
unsafe { self.0.unlock() };
}
}