#![allow(dead_code)]
use alloc::sync::Arc;
use core::{
cell::UnsafeCell,
fmt,
ops::{Deref, DerefMut},
sync::atomic::{AtomicBool, Ordering},
};
use crate::{
task::{disable_preempt, DisablePreemptGuard},
trap::{disable_local, DisabledLocalIrqGuard},
};
pub struct SpinLock<T: ?Sized> {
lock: AtomicBool,
val: UnsafeCell<T>,
}
impl<T> SpinLock<T> {
pub const fn new(val: T) -> Self {
Self {
lock: AtomicBool::new(false),
val: UnsafeCell::new(val),
}
}
}
impl<T: ?Sized> SpinLock<T> {
pub fn lock_irq_disabled(&self) -> SpinLockGuard<T> {
let guard = disable_local();
self.acquire_lock();
SpinLockGuard_ {
lock: self,
inner_guard: InnerGuard::IrqGuard(guard),
}
}
pub fn try_lock_irq_disabled(&self) -> Option<SpinLockGuard<T>> {
let irq_guard = disable_local();
if self.try_acquire_lock() {
let lock_guard = SpinLockGuard_ {
lock: self,
inner_guard: InnerGuard::IrqGuard(irq_guard),
};
return Some(lock_guard);
}
None
}
pub fn lock(&self) -> SpinLockGuard<T> {
let guard = disable_preempt();
self.acquire_lock();
SpinLockGuard_ {
lock: self,
inner_guard: InnerGuard::PreemptGuard(guard),
}
}
pub fn lock_arc(self: &Arc<Self>) -> ArcSpinLockGuard<T> {
let guard = disable_preempt();
self.acquire_lock();
SpinLockGuard_ {
lock: self.clone(),
inner_guard: InnerGuard::PreemptGuard(guard),
}
}
pub fn try_lock(&self) -> Option<SpinLockGuard<T>> {
let guard = disable_preempt();
if self.try_acquire_lock() {
let lock_guard = SpinLockGuard_ {
lock: self,
inner_guard: InnerGuard::PreemptGuard(guard),
};
return Some(lock_guard);
}
None
}
fn acquire_lock(&self) {
while !self.try_acquire_lock() {
core::hint::spin_loop();
}
}
fn try_acquire_lock(&self) -> bool {
self.lock
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_ok()
}
fn release_lock(&self) {
self.lock.store(false, Ordering::Release);
}
}
impl<T: ?Sized + fmt::Debug> fmt::Debug for SpinLock<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.val, f)
}
}
unsafe impl<T: ?Sized + Send> Send for SpinLock<T> {}
unsafe impl<T: ?Sized + Send> Sync for SpinLock<T> {}
enum InnerGuard {
IrqGuard(DisabledLocalIrqGuard),
PreemptGuard(DisablePreemptGuard),
}
pub type SpinLockGuard<'a, T> = SpinLockGuard_<T, &'a SpinLock<T>>;
pub type ArcSpinLockGuard<T> = SpinLockGuard_<T, Arc<SpinLock<T>>>;
pub struct SpinLockGuard_<T: ?Sized, R: Deref<Target = SpinLock<T>>> {
inner_guard: InnerGuard,
lock: R,
}
impl<T: ?Sized, R: Deref<Target = SpinLock<T>>> Deref for SpinLockGuard_<T, R> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.lock.val.get() }
}
}
impl<T: ?Sized, R: Deref<Target = SpinLock<T>>> DerefMut for SpinLockGuard_<T, R> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.lock.val.get() }
}
}
impl<T: ?Sized, R: Deref<Target = SpinLock<T>>> Drop for SpinLockGuard_<T, R> {
fn drop(&mut self) {
self.lock.release_lock();
}
}
impl<T: ?Sized + fmt::Debug, R: Deref<Target = SpinLock<T>>> fmt::Debug for SpinLockGuard_<T, R> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<T: ?Sized, R: Deref<Target = SpinLock<T>>> !Send for SpinLockGuard_<T, R> {}
unsafe impl<T: ?Sized + Sync, R: Deref<Target = SpinLock<T>> + Sync> Sync for SpinLockGuard_<T, R> {}