#[cfg(feature = "smp")]
use core::sync::atomic::AtomicBool;
use core::{
cell::UnsafeCell,
fmt,
marker::PhantomData,
ops::{Deref, DerefMut},
};
use crate::sync::context::GuardState;
#[cfg(feature = "lockdep")]
use crate::sync::context::IrqSaveGuard;
#[cfg(feature = "lockdep")]
type LockdepAcquire = super::lockdep::Lockdep;
#[cfg(not(feature = "lockdep"))]
#[derive(Clone, Copy)]
struct LockdepAcquire;
#[cfg(not(feature = "lockdep"))]
impl LockdepAcquire {
#[inline(always)]
#[track_caller]
fn prepare<G: GuardState, T: ?Sized>(_lock: &BaseSpinLock<G, T>, _is_try: bool) -> Self {
Self
}
#[inline(always)]
#[track_caller]
fn prepare_nested<G: GuardState, T: ?Sized>(
_lock: &BaseSpinLock<G, T>,
_is_try: bool,
_subclass: u32,
) -> Self {
Self
}
#[cfg(feature = "smp")]
#[inline(always)]
fn finish(&self, _acquired: bool) {}
}
#[repr(C)]
pub struct BaseSpinLock<G: GuardState, T: ?Sized> {
_phantom: PhantomData<G>,
#[cfg(feature = "smp")]
lock: AtomicBool,
#[cfg(feature = "lockdep")]
lockdep: super::lockdep::LockdepMap,
data: UnsafeCell<T>,
}
pub struct BaseSpinLockGuard<'a, G: GuardState, T: ?Sized + 'a> {
_phantom: &'a PhantomData<G>,
_not_send: PhantomData<*mut ()>,
irq_state: G::State,
#[cfg(feature = "lockdep")]
lock_addr: usize,
data: *mut T,
#[cfg(feature = "smp")]
lock: &'a AtomicBool,
}
unsafe impl<G: GuardState, T: ?Sized + Send> Sync for BaseSpinLock<G, T> {}
unsafe impl<G: GuardState, T: ?Sized + Send> Send for BaseSpinLock<G, T> {}
impl<G: GuardState, T> BaseSpinLock<G, T> {
#[inline(always)]
#[track_caller]
pub const fn new(data: T) -> Self {
Self {
_phantom: PhantomData,
data: UnsafeCell::new(data),
#[cfg(feature = "smp")]
lock: AtomicBool::new(false),
#[cfg(feature = "lockdep")]
lockdep: super::lockdep::LockdepMap::new(),
}
}
#[inline(always)]
pub fn into_inner(self) -> T {
let BaseSpinLock { data, .. } = self;
data.into_inner()
}
}
impl<G: GuardState, T: ?Sized> BaseSpinLock<G, T> {
#[cfg(feature = "lockdep")]
#[inline(always)]
pub(crate) fn lockdep_map(&self) -> &super::lockdep::LockdepMap {
&self.lockdep
}
#[inline(always)]
#[cfg(not(feature = "smp"))]
fn finish_lockdep_with_irqsave(lockdep: LockdepAcquire) {
#[cfg(feature = "lockdep")]
{
let _lockdep_irq_guard = IrqSaveGuard::new();
lockdep.finish(true);
}
#[cfg(not(feature = "lockdep"))]
{
let _ = lockdep;
}
}
#[inline(always)]
#[cfg(feature = "smp")]
fn acquire_once_weak(&self, lockdep: LockdepAcquire) -> bool {
#[cfg(feature = "lockdep")]
let _lockdep_irq_guard = IrqSaveGuard::new();
let acquired = super::atomic::spin_try_acquire_weak(&self.lock);
if acquired {
lockdep.finish(true);
}
acquired
}
#[inline(always)]
#[cfg(feature = "smp")]
fn acquire_once_strong(&self, lockdep: LockdepAcquire) -> bool {
#[cfg(feature = "lockdep")]
let _lockdep_irq_guard = IrqSaveGuard::new();
let acquired = super::atomic::spin_try_acquire_strong(&self.lock);
if acquired {
lockdep.finish(true);
}
acquired
}
#[inline(always)]
fn blocking_acquire(&self, lockdep: LockdepAcquire) {
cfg_if::cfg_if! {
if #[cfg(feature = "smp")] {
super::atomic::spin_acquire(&self.lock, || self.acquire_once_weak(lockdep));
} else {
Self::finish_lockdep_with_irqsave(lockdep);
}
}
}
#[inline(always)]
fn try_acquire(&self, lockdep: LockdepAcquire) -> bool {
cfg_if::cfg_if! {
if #[cfg(feature = "smp")] {
self.acquire_once_strong(lockdep)
} else {
Self::finish_lockdep_with_irqsave(lockdep);
true
}
}
}
#[inline(always)]
#[track_caller]
pub fn lock(&self) -> BaseSpinLockGuard<'_, G, T> {
self.lock_nested(0)
}
#[inline(always)]
#[track_caller]
pub fn lock_nested(&self, subclass: u32) -> BaseSpinLockGuard<'_, G, T> {
let irq_state = G::acquire();
let lockdep = LockdepAcquire::prepare_nested(self, false, subclass);
self.blocking_acquire(lockdep);
BaseSpinLockGuard {
_phantom: &PhantomData,
_not_send: PhantomData,
irq_state,
#[cfg(feature = "lockdep")]
lock_addr: lockdep.lock_addr(),
data: unsafe { &mut *self.data.get() },
#[cfg(feature = "smp")]
lock: &self.lock,
}
}
#[inline(always)]
pub fn is_locked(&self) -> bool {
cfg_if::cfg_if! {
if #[cfg(feature = "smp")] {
super::atomic::spin_is_locked(&self.lock)
} else {
false
}
}
}
#[inline(always)]
#[track_caller]
pub fn try_lock(&self) -> Option<BaseSpinLockGuard<'_, G, T>> {
let irq_state = G::acquire();
let lockdep = LockdepAcquire::prepare(self, true);
let is_unlocked = self.try_acquire(lockdep);
#[cfg(feature = "lockdep")]
if !is_unlocked {
lockdep.finish(false);
}
if is_unlocked {
Some(BaseSpinLockGuard {
_phantom: &PhantomData,
_not_send: PhantomData,
irq_state,
#[cfg(feature = "lockdep")]
lock_addr: lockdep.lock_addr(),
data: unsafe { &mut *self.data.get() },
#[cfg(feature = "smp")]
lock: &self.lock,
})
} else {
G::release(irq_state);
None
}
}
#[inline(always)]
pub unsafe fn force_unlock(&self) {
#[cfg(feature = "lockdep")]
let _lockdep_irq_guard = IrqSaveGuard::new();
#[cfg(feature = "lockdep")]
{
let addr = self as *const _ as *const () as usize;
super::lockdep::force_release::<G>(addr);
}
#[cfg(feature = "smp")]
super::atomic::spin_release(&self.lock);
}
#[inline(always)]
pub fn get_mut(&mut self) -> &mut T {
unsafe { &mut *self.data.get() }
}
}
impl<G: GuardState, T: Default> Default for BaseSpinLock<G, T> {
#[inline(always)]
fn default() -> Self {
Self::new(Default::default())
}
}
impl<G: GuardState, T: ?Sized + fmt::Debug> fmt::Debug for BaseSpinLock<G, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.try_lock() {
Some(guard) => write!(f, "RawSpinLock {{ data: ")
.and_then(|()| (*guard).fmt(f))
.and_then(|()| write!(f, "}}")),
None => write!(f, "RawSpinLock {{ <locked> }}"),
}
}
}
impl<G: GuardState, T: ?Sized> Deref for BaseSpinLockGuard<'_, G, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &T {
unsafe { &*self.data }
}
}
impl<G: GuardState, T: ?Sized> DerefMut for BaseSpinLockGuard<'_, G, T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.data }
}
}
impl<G: GuardState, T: ?Sized + fmt::Debug> fmt::Debug for BaseSpinLockGuard<'_, G, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<G: GuardState, T: ?Sized> Drop for BaseSpinLockGuard<'_, G, T> {
#[inline(always)]
fn drop(&mut self) {
{
#[cfg(feature = "lockdep")]
let _lockdep_irq_guard = IrqSaveGuard::new();
#[cfg(feature = "lockdep")]
super::lockdep::release::<G>(self.lock_addr);
#[cfg(feature = "smp")]
super::atomic::spin_release(self.lock);
}
G::release(self.irq_state);
}
}