new: 新增具有守卫的自旋锁SpinLock,支持编译期对锁的使用进行检查。 (#148)

This commit is contained in:
login
2023-01-14 10:35:49 +08:00
committed by GitHub
parent 41474ba3df
commit ec53d23ed0
6 changed files with 169 additions and 14 deletions

View File

@ -23,12 +23,12 @@ mod include;
mod ipc;
#[macro_use]
mod libs;
mod exception;
mod mm;
mod process;
mod sched;
mod smp;
mod time;
mod exception;
extern crate alloc;

View File

@ -1,4 +1,6 @@
#![allow(dead_code)]
use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};
use core::ptr::read_volatile;
use core::sync::atomic::{AtomicBool, Ordering};
@ -59,7 +61,7 @@ pub fn spin_unlock_irq(lock: *mut spinlock_t) {
/// 原始的Spinlock自旋锁
/// 请注意这个自旋锁和C的不兼容。
///
///
/// @param self.0 这个AtomicBool的值为false时表示没有被加锁。当它为true时表示自旋锁已经被上锁。
#[derive(Debug)]
pub struct RawSpinlock(AtomicBool);
@ -69,12 +71,12 @@ impl RawSpinlock {
pub const INIT: RawSpinlock = RawSpinlock(AtomicBool::new(false));
/// @brief 加锁
pub fn lock(&mut self) {
pub fn lock(&self) {
while !self.try_lock() {}
}
/// @brief 关中断并加锁
pub fn lock_irq(&mut self){
pub fn lock_irq(&self) {
cli();
self.lock();
}
@ -82,7 +84,7 @@ impl RawSpinlock {
/// @brief 尝试加锁
/// @return 加锁成功->true
/// 加锁失败->false
pub fn try_lock(&mut self) -> bool {
pub fn try_lock(&self) -> bool {
// 先增加自旋锁持有计数
preempt_disable();
@ -90,7 +92,7 @@ impl RawSpinlock {
.0
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_ok();
// 如果加锁失败恢复自旋锁持有计数
if res == false {
preempt_enable();
@ -99,34 +101,92 @@ impl RawSpinlock {
}
/// @brief 解锁
pub fn unlock(&mut self){
pub fn unlock(&self) {
// 减少自旋锁持有计数
preempt_enable();
self.0.store(false, Ordering::Release);
}
/// @brief 放锁并开中断
pub fn unlock_irq(&mut self){
pub fn unlock_irq(&self) {
self.unlock();
sti();
}
/// @brief 判断自旋锁是否被上锁
///
///
/// @return true 自旋锁被上锁
/// @return false 自旋锁处于解锁状态
pub fn is_locked(&self)->bool
{
pub fn is_locked(&self) -> bool {
return self.0.load(Ordering::Relaxed).into();
}
/// @brief 强制设置自旋锁的状态
/// 请注意这样操作可能会带来未知的风险。因此它是unsafe的。尽管从Rust语言本身来说它是safe的
pub unsafe fn set_value(&mut self, value:bool){
pub unsafe fn set_value(&mut self, value: bool) {
self.0.store(value, Ordering::SeqCst);
}
// todo: spin_lock_irqsave
// todo: spin_unlock_irqrestore
}
/// 实现了守卫的SpinLock, 能够支持内部可变性
///
#[derive(Debug)]
pub struct SpinLock<T> {
lock: RawSpinlock,
/// 自旋锁保护的数据
data: UnsafeCell<T>,
}
/// SpinLock的守卫
/// 该守卫没有构造器并且其信息均为私有的。我们只能通过SpinLock的lock()方法获得一个守卫。
/// 因此我们可以认为,只要能够获得一个守卫,那么数据就在自旋锁的保护之下。
#[derive(Debug)]
pub struct SpinLockGuard<'a, T: 'a> {
lock: &'a SpinLock<T>,
}
/// 向编译器保证SpinLock在线程之间是安全的.
/// 其中要求类型T实现了Send这个Trait
unsafe impl<T> Sync for SpinLock<T> where T: Send {}
impl<T> SpinLock<T> {
pub const fn new(value: T) -> Self {
return Self {
lock: RawSpinlock::INIT,
data: UnsafeCell::new(value),
};
}
#[inline(always)]
pub fn lock(&self) -> SpinLockGuard<T> {
self.lock.lock();
// 加锁成功,返回一个守卫
return SpinLockGuard { lock: self };
}
}
/// 实现Deref trait支持通过获取SpinLockGuard来获取临界区数据的不可变引用
impl<T> Deref for SpinLockGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
return unsafe { &*self.lock.data.get() };
}
}
/// 实现DerefMut trait支持通过获取SpinLockGuard来获取临界区数据的可变引用
impl<T> DerefMut for SpinLockGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
return unsafe { &mut *self.lock.data.get() };
}
}
/// @brief 为SpinLockGuard实现Drop方法那么一旦守卫的生命周期结束就会自动释放自旋锁避免了忘记放锁的情况
impl<T> Drop for SpinLockGuard<'_, T> {
fn drop(&mut self) {
self.lock.lock.unlock();
}
}