xref: /DragonOS/kernel/src/libs/mutex.rs (revision f0c87a897fe813b7f06bf5a9e93c43ad9519dafd)
1935f40ecSlogin use core::{
2935f40ecSlogin     cell::UnsafeCell,
3935f40ecSlogin     ops::{Deref, DerefMut},
4935f40ecSlogin };
5935f40ecSlogin 
61496ba7bSLoGin use alloc::{collections::LinkedList, sync::Arc};
791e9d4abSLoGin use system_error::SystemError;
8935f40ecSlogin 
9935f40ecSlogin use crate::{
10*f0c87a89SGnoCiYeH     arch::CurrentIrqArch,
111496ba7bSLoGin     exception::InterruptArch,
1278bf93f0SYJwu2023     libs::spinlock::SpinLockGuard,
131496ba7bSLoGin     process::{Pid, ProcessControlBlock, ProcessManager},
14*f0c87a89SGnoCiYeH     sched::{schedule, SchedMode},
15935f40ecSlogin };
16935f40ecSlogin 
17935f40ecSlogin use super::spinlock::SpinLock;
18935f40ecSlogin 
19935f40ecSlogin #[derive(Debug)]
20935f40ecSlogin struct MutexInner {
21935f40ecSlogin     /// 当前Mutex是否已经被上锁(上锁时,为true)
22935f40ecSlogin     is_locked: bool,
23935f40ecSlogin     /// 等待获得这个锁的进程的链表
241496ba7bSLoGin     wait_list: LinkedList<Arc<ProcessControlBlock>>,
25935f40ecSlogin }
26935f40ecSlogin 
27935f40ecSlogin /// @brief Mutex互斥量结构体
28935f40ecSlogin /// 请注意!由于Mutex属于休眠锁,因此,如果您的代码可能在中断上下文内执行,请勿采用Mutex!
29935f40ecSlogin #[derive(Debug)]
30935f40ecSlogin pub struct Mutex<T> {
31935f40ecSlogin     /// 该Mutex保护的数据
32935f40ecSlogin     data: UnsafeCell<T>,
33935f40ecSlogin     /// Mutex内部的信息
34935f40ecSlogin     inner: SpinLock<MutexInner>,
35935f40ecSlogin }
36935f40ecSlogin 
37935f40ecSlogin /// @brief Mutex的守卫
38935f40ecSlogin #[derive(Debug)]
39935f40ecSlogin pub struct MutexGuard<'a, T: 'a> {
40935f40ecSlogin     lock: &'a Mutex<T>,
41935f40ecSlogin }
42935f40ecSlogin 
43935f40ecSlogin unsafe impl<T> Sync for Mutex<T> where T: Send {}
44935f40ecSlogin 
45935f40ecSlogin impl<T> Mutex<T> {
46935f40ecSlogin     /// @brief 初始化一个新的Mutex对象
47935f40ecSlogin     #[allow(dead_code)]
new(value: T) -> Self48935f40ecSlogin     pub const fn new(value: T) -> Self {
49935f40ecSlogin         return Self {
50935f40ecSlogin             data: UnsafeCell::new(value),
51935f40ecSlogin             inner: SpinLock::new(MutexInner {
52935f40ecSlogin                 is_locked: false,
531496ba7bSLoGin                 wait_list: LinkedList::new(),
54935f40ecSlogin             }),
55935f40ecSlogin         };
56935f40ecSlogin     }
57935f40ecSlogin 
58935f40ecSlogin     /// @brief 对Mutex加锁
59935f40ecSlogin     /// @return MutexGuard<T> 返回Mutex的守卫,您可以使用这个守卫来操作被保护的数据
60935f40ecSlogin     #[inline(always)]
61935f40ecSlogin     #[allow(dead_code)]
lock(&self) -> MutexGuard<T>62935f40ecSlogin     pub fn lock(&self) -> MutexGuard<T> {
63935f40ecSlogin         loop {
64935f40ecSlogin             let mut inner: SpinLockGuard<MutexInner> = self.inner.lock();
65935f40ecSlogin             // 当前mutex已经上锁
66935f40ecSlogin             if inner.is_locked {
67935f40ecSlogin                 // 检查当前进程是否处于等待队列中,如果不在,就加到等待队列内
68b5b571e0SLoGin                 if !self.check_pid_in_wait_list(&inner, ProcessManager::current_pcb().pid()) {
691496ba7bSLoGin                     inner.wait_list.push_back(ProcessManager::current_pcb());
70935f40ecSlogin                 }
71935f40ecSlogin 
72935f40ecSlogin                 // 加到等待唤醒的队列,然后睡眠
73935f40ecSlogin                 drop(inner);
74935f40ecSlogin                 self.__sleep();
75935f40ecSlogin             } else {
76935f40ecSlogin                 // 加锁成功
77935f40ecSlogin                 inner.is_locked = true;
78935f40ecSlogin                 drop(inner);
79935f40ecSlogin                 break;
80935f40ecSlogin             }
81935f40ecSlogin         }
82935f40ecSlogin 
83935f40ecSlogin         // 加锁成功,返回一个守卫
84935f40ecSlogin         return MutexGuard { lock: self };
85935f40ecSlogin     }
86935f40ecSlogin 
87935f40ecSlogin     /// @brief 尝试对Mutex加锁。如果加锁失败,不会将当前进程加入等待队列。
88935f40ecSlogin     /// @return Ok 加锁成功,返回Mutex的守卫
89935f40ecSlogin     /// @return Err 如果Mutex当前已经上锁,则返回Err.
90935f40ecSlogin     #[inline(always)]
91935f40ecSlogin     #[allow(dead_code)]
try_lock(&self) -> Result<MutexGuard<T>, SystemError>92676b8ef6SMork     pub fn try_lock(&self) -> Result<MutexGuard<T>, SystemError> {
93935f40ecSlogin         let mut inner = self.inner.lock();
94935f40ecSlogin 
95935f40ecSlogin         // 如果当前mutex已经上锁,则失败
96935f40ecSlogin         if inner.is_locked {
97676b8ef6SMork             return Err(SystemError::EBUSY);
98935f40ecSlogin         } else {
99935f40ecSlogin             // 加锁成功
100935f40ecSlogin             inner.is_locked = true;
101935f40ecSlogin             return Ok(MutexGuard { lock: self });
102935f40ecSlogin         }
103935f40ecSlogin     }
104935f40ecSlogin 
105935f40ecSlogin     /// @brief Mutex内部的睡眠函数
__sleep(&self)106935f40ecSlogin     fn __sleep(&self) {
1071496ba7bSLoGin         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
1081496ba7bSLoGin         ProcessManager::mark_sleep(true).ok();
1091496ba7bSLoGin         drop(irq_guard);
110*f0c87a89SGnoCiYeH         schedule(SchedMode::SM_NONE);
111935f40ecSlogin     }
112935f40ecSlogin 
113935f40ecSlogin     /// @brief 放锁。
114935f40ecSlogin     ///
115935f40ecSlogin     /// 本函数只能是私有的,且只能被守卫的drop方法调用,否则将无法保证并发安全。
unlock(&self)116935f40ecSlogin     fn unlock(&self) {
117935f40ecSlogin         let mut inner: SpinLockGuard<MutexInner> = self.inner.lock();
118935f40ecSlogin         // 当前mutex一定是已经加锁的状态
119935f40ecSlogin         assert!(inner.is_locked);
120935f40ecSlogin         // 标记mutex已经解锁
121935f40ecSlogin         inner.is_locked = false;
122935f40ecSlogin         if inner.wait_list.is_empty() {
123935f40ecSlogin             return;
124935f40ecSlogin         }
125935f40ecSlogin 
126935f40ecSlogin         // wait_list不为空,则获取下一个要被唤醒的进程的pcb
1271496ba7bSLoGin         let to_wakeup: Arc<ProcessControlBlock> = inner.wait_list.pop_front().unwrap();
128935f40ecSlogin         drop(inner);
129935f40ecSlogin 
1301496ba7bSLoGin         ProcessManager::wakeup(&to_wakeup).ok();
131935f40ecSlogin     }
132935f40ecSlogin 
133935f40ecSlogin     /// @brief 检查进程是否在该mutex的等待队列内
134935f40ecSlogin     #[inline]
check_pid_in_wait_list(&self, inner: &MutexInner, pid: Pid) -> bool1351496ba7bSLoGin     fn check_pid_in_wait_list(&self, inner: &MutexInner, pid: Pid) -> bool {
136935f40ecSlogin         for p in inner.wait_list.iter() {
1371496ba7bSLoGin             if p.pid() == pid {
138935f40ecSlogin                 // 在等待队列内
139935f40ecSlogin                 return true;
140935f40ecSlogin             }
141935f40ecSlogin         }
142935f40ecSlogin 
143935f40ecSlogin         // 不在等待队列内
144935f40ecSlogin         return false;
145935f40ecSlogin     }
146935f40ecSlogin }
147935f40ecSlogin 
148935f40ecSlogin /// 实现Deref trait,支持通过获取MutexGuard来获取临界区数据的不可变引用
149935f40ecSlogin impl<T> Deref for MutexGuard<'_, T> {
150935f40ecSlogin     type Target = T;
151935f40ecSlogin 
deref(&self) -> &Self::Target152935f40ecSlogin     fn deref(&self) -> &Self::Target {
153935f40ecSlogin         return unsafe { &*self.lock.data.get() };
154935f40ecSlogin     }
155935f40ecSlogin }
156935f40ecSlogin 
157935f40ecSlogin /// 实现DerefMut trait,支持通过获取MutexGuard来获取临界区数据的可变引用
158935f40ecSlogin impl<T> DerefMut for MutexGuard<'_, T> {
deref_mut(&mut self) -> &mut Self::Target159935f40ecSlogin     fn deref_mut(&mut self) -> &mut Self::Target {
160935f40ecSlogin         return unsafe { &mut *self.lock.data.get() };
161935f40ecSlogin     }
162935f40ecSlogin }
163935f40ecSlogin 
164935f40ecSlogin /// @brief 为MutexGuard实现Drop方法,那么,一旦守卫的生命周期结束,就会自动释放自旋锁,避免了忘记放锁的情况
165935f40ecSlogin impl<T> Drop for MutexGuard<'_, T> {
drop(&mut self)166935f40ecSlogin     fn drop(&mut self) {
167935f40ecSlogin         self.lock.unlock();
168935f40ecSlogin     }
169935f40ecSlogin }
170