#[cfg(feature = "smp")]
use core::sync::atomic::{AtomicBool, Ordering};
use core::{cell::UnsafeCell, marker::PhantomData};
use ax_kernel_guard::{BaseGuard, NoPreemptIrqSave};
pub struct BaseRawSpinLock<G: BaseGuard> {
_phantom: PhantomData<G>,
#[cfg(feature = "smp")]
locked: AtomicBool,
state: UnsafeCell<Option<G::State>>,
}
unsafe impl<G: BaseGuard> Sync for BaseRawSpinLock<G> {}
impl<G: BaseGuard> 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: BaseGuard> Default for BaseRawSpinLock<G> {
fn default() -> Self {
Self::new()
}
}
unsafe impl<G: BaseGuard + 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);
}
}
pub type RawSpinNoIrq = BaseRawSpinLock<NoPreemptIrqSave>;