From 5277886b5da209384df392474e42b54609b06547 Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Tue, 4 Apr 2023 01:23:08 -0400 Subject: [PATCH] Add Spinlock primitive with disabling IRQ --- src/framework/jinux-frame/src/sync/spin.rs | 87 ++++++++++++++++++---- 1 file changed, 73 insertions(+), 14 deletions(-) diff --git a/src/framework/jinux-frame/src/sync/spin.rs b/src/framework/jinux-frame/src/sync/spin.rs index 1b92ff1a..2a09b523 100644 --- a/src/framework/jinux-frame/src/sync/spin.rs +++ b/src/framework/jinux-frame/src/sync/spin.rs @@ -1,47 +1,106 @@ -use core::ops::{Deref, DerefMut}; +use core::cell::UnsafeCell; +use core::sync::atomic::Ordering; +use core::{ + ops::{Deref, DerefMut}, + sync::atomic::AtomicBool, +}; + +use crate::sync::disable_local; +use crate::sync::irq::DisabledLocalIrqGuard; +use core::fmt; /// A spin lock. -pub struct SpinLock { - val: T, +pub struct SpinLock { + val: UnsafeCell, + lock: AtomicBool, } impl SpinLock { /// Creates a new spin lock. - pub fn new(val: T) -> Self { - todo!() + pub const fn new(val: T) -> Self { + Self { + val: UnsafeCell::new(val), + lock: AtomicBool::new(false), + } } /// Acquire the spin lock. /// /// This method runs in a busy loop until the lock can be acquired. /// After acquiring the spin lock, all interrupts are disabled. - pub fn lock<'a>(&self) -> SpinLockGuard<'a, T> { - todo!() + pub fn lock(&self) -> SpinLockGuard { + // FIXME: add disable_preemption + let guard = disable_local(); + self.access_lock(); + SpinLockGuard { + lock: &self, + irq_guard: guard, + } + } + + /// Access the spin lock, otherwise busy waiting + fn access_lock(&self) { + while !self.try_access_lock() { + core::hint::spin_loop(); + } + } + + fn try_access_lock(&self) -> bool { + self.lock + .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst) + .is_ok() + } + + fn release_lock(&self) { + self.lock.store(false, Ordering::SeqCst); } } -unsafe impl Send for SpinLock {} -unsafe impl Sync for SpinLock {} +impl fmt::Debug for SpinLock { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.val, f) + } +} + +// Safety. Only a single lock holder is permitted to access the inner data of Spinlock. +unsafe impl Send for SpinLock {} +unsafe impl Sync for SpinLock {} /// The guard of a spin lock. -pub struct SpinLockGuard<'a, T: ?Sized + 'a> { +pub struct SpinLockGuard<'a, T> { lock: &'a SpinLock, + irq_guard: DisabledLocalIrqGuard, } impl<'a, T> Deref for SpinLockGuard<'a, T> { type Target = T; fn deref(&self) -> &T { - todo!() + unsafe { &mut *self.lock.val.get() } } } impl<'a, T> DerefMut for SpinLockGuard<'a, T> { fn deref_mut(&mut self) -> &mut Self::Target { - todo!() + unsafe { &mut *self.lock.val.get() } } } -impl<'a, T: ?Sized> !Send for SpinLockGuard<'a, T> {} +impl<'a, T> Drop for SpinLockGuard<'a, T> { + fn drop(&mut self) { + self.lock.release_lock(); + } +} -unsafe impl Sync for SpinLockGuard<'_, T> {} +impl<'a, T: fmt::Debug> fmt::Debug for SpinLockGuard<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +// SpinLockGuard cannot be sent between tasks/threads +impl<'a, T> !Send for SpinLockGuard<'a, T> {} + +// Safety. SpinLockGuard can be shared between tasks/threads in same CPU. +// As SpinLock disables interrupts to prevent race conditions caused by interrupts. +unsafe impl Sync for SpinLockGuard<'_, T> {}