new: Rust版本的Mutex (#157)

This commit is contained in:
login
2023-01-17 21:30:16 +08:00
committed by GitHub
parent d8a064128a
commit 935f40ec17
8 changed files with 364 additions and 58 deletions

View File

@ -29,4 +29,5 @@
#include <mm/mm.h>
#include <mm/slab.h>
#include <process/process.h>
#include <sched/sched.h>
#include <sched/sched.h>
#include <time/sleep.h>

View File

@ -1,5 +1,6 @@
#![no_std] // <1>
#![no_main] // <1>
#![feature(const_mut_refs)]
#![feature(core_intrinsics)] // <2>
#![feature(alloc_error_handler)]
#![feature(panic_info_message)]

View File

@ -6,4 +6,5 @@ pub mod refcount;
pub mod atomic;
pub mod list;
pub mod lockref;
pub mod mutex;
pub mod wait_queue;

169
kernel/src/libs/mutex.rs Normal file
View File

@ -0,0 +1,169 @@
use core::{
cell::UnsafeCell,
ops::{Deref, DerefMut},
};
use alloc::collections::LinkedList;
use crate::{
arch::{asm::current::current_pcb, sched::sched},
include::bindings::bindings::{
pid_t, process_control_block, process_wakeup, EBUSY, PROC_INTERRUPTIBLE, PROC_RUNNING,
},
libs::spinlock::SpinLockGuard,
};
use super::spinlock::SpinLock;
#[derive(Debug)]
struct MutexInner {
/// 当前Mutex是否已经被上锁(上锁时为true)
is_locked: bool,
/// 等待获得这个锁的进程的链表
wait_list: LinkedList<&'static mut process_control_block>,
}
/// @brief Mutex互斥量结构体
/// 请注意由于Mutex属于休眠锁因此如果您的代码可能在中断上下文内执行请勿采用Mutex
#[derive(Debug)]
pub struct Mutex<T> {
/// 该Mutex保护的数据
data: UnsafeCell<T>,
/// Mutex内部的信息
inner: SpinLock<MutexInner>,
}
/// @brief Mutex的守卫
#[derive(Debug)]
pub struct MutexGuard<'a, T: 'a> {
lock: &'a Mutex<T>,
}
unsafe impl<T> Sync for Mutex<T> where T: Send {}
impl<T> Mutex<T> {
/// @brief 初始化一个新的Mutex对象
#[allow(dead_code)]
pub const fn new(value: T) -> Self {
return Self {
data: UnsafeCell::new(value),
inner: SpinLock::new(MutexInner {
is_locked: false,
wait_list: LinkedList::<&'static mut process_control_block>::new(),
}),
};
}
/// @brief 对Mutex加锁
/// @return MutexGuard<T> 返回Mutex的守卫您可以使用这个守卫来操作被保护的数据
#[inline(always)]
#[allow(dead_code)]
pub fn lock(&self) -> MutexGuard<T> {
loop {
let mut inner: SpinLockGuard<MutexInner> = self.inner.lock();
// 当前mutex已经上锁
if inner.is_locked {
// 检查当前进程是否处于等待队列中,如果不在,就加到等待队列内
if self.check_pid_in_wait_list(&inner, current_pcb().pid) == false {
inner.wait_list.push_back(current_pcb());
}
// 加到等待唤醒的队列,然后睡眠
drop(inner);
self.__sleep();
} else {
// 加锁成功
inner.is_locked = true;
drop(inner);
break;
}
}
// 加锁成功,返回一个守卫
return MutexGuard { lock: self };
}
/// @brief 尝试对Mutex加锁。如果加锁失败不会将当前进程加入等待队列。
/// @return Ok 加锁成功返回Mutex的守卫
/// @return Err 如果Mutex当前已经上锁则返回Err.
#[inline(always)]
#[allow(dead_code)]
pub fn try_lock(&self) -> Result<MutexGuard<T>, i32> {
let mut inner = self.inner.lock();
// 如果当前mutex已经上锁则失败
if inner.is_locked {
return Err(-(EBUSY as i32));
} else {
// 加锁成功
inner.is_locked = true;
return Ok(MutexGuard { lock: self });
}
}
/// @brief Mutex内部的睡眠函数
fn __sleep(&self) {
current_pcb().state &= !(PROC_RUNNING as u64);
current_pcb().state |= PROC_INTERRUPTIBLE as u64;
sched();
}
/// @brief 放锁。
///
/// 本函数只能是私有的且只能被守卫的drop方法调用否则将无法保证并发安全。
fn unlock(&self) {
let mut inner: SpinLockGuard<MutexInner> = self.inner.lock();
// 当前mutex一定是已经加锁的状态
assert!(inner.is_locked);
// 标记mutex已经解锁
inner.is_locked = false;
if inner.wait_list.is_empty() {
return;
}
// wait_list不为空则获取下一个要被唤醒的进程的pcb
let to_wakeup: &mut process_control_block = inner.wait_list.pop_front().unwrap();
drop(inner);
unsafe {
process_wakeup(to_wakeup);
}
}
/// @brief 检查进程是否在该mutex的等待队列内
#[inline]
fn check_pid_in_wait_list(&self, inner: &MutexInner, pid: pid_t) -> bool {
for p in inner.wait_list.iter() {
if p.pid == pid {
// 在等待队列内
return true;
}
}
// 不在等待队列内
return false;
}
}
/// 实现Deref trait支持通过获取MutexGuard来获取临界区数据的不可变引用
impl<T> Deref for MutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
return unsafe { &*self.lock.data.get() };
}
}
/// 实现DerefMut trait支持通过获取MutexGuard来获取临界区数据的可变引用
impl<T> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
return unsafe { &mut *self.lock.data.get() };
}
}
/// @brief 为MutexGuard实现Drop方法那么一旦守卫的生命周期结束就会自动释放自旋锁避免了忘记放锁的情况
impl<T> Drop for MutexGuard<'_, T> {
fn drop(&mut self) {
self.lock.unlock();
}
}