xref: /DragonOS/kernel/src/libs/mutex.rs (revision 935f40ec174fec217aed4553d45996327443bc0e)
1*935f40ecSlogin use core::{
2*935f40ecSlogin     cell::UnsafeCell,
3*935f40ecSlogin     ops::{Deref, DerefMut},
4*935f40ecSlogin };
5*935f40ecSlogin 
6*935f40ecSlogin use alloc::collections::LinkedList;
7*935f40ecSlogin 
8*935f40ecSlogin use crate::{
9*935f40ecSlogin     arch::{asm::current::current_pcb, sched::sched},
10*935f40ecSlogin     include::bindings::bindings::{
11*935f40ecSlogin         pid_t, process_control_block, process_wakeup, EBUSY, PROC_INTERRUPTIBLE, PROC_RUNNING,
12*935f40ecSlogin     },
13*935f40ecSlogin     libs::spinlock::SpinLockGuard,
14*935f40ecSlogin };
15*935f40ecSlogin 
16*935f40ecSlogin use super::spinlock::SpinLock;
17*935f40ecSlogin 
18*935f40ecSlogin #[derive(Debug)]
19*935f40ecSlogin struct MutexInner {
20*935f40ecSlogin     /// 当前Mutex是否已经被上锁(上锁时,为true)
21*935f40ecSlogin     is_locked: bool,
22*935f40ecSlogin     /// 等待获得这个锁的进程的链表
23*935f40ecSlogin     wait_list: LinkedList<&'static mut process_control_block>,
24*935f40ecSlogin }
25*935f40ecSlogin 
26*935f40ecSlogin /// @brief Mutex互斥量结构体
27*935f40ecSlogin /// 请注意!由于Mutex属于休眠锁,因此,如果您的代码可能在中断上下文内执行,请勿采用Mutex!
28*935f40ecSlogin #[derive(Debug)]
29*935f40ecSlogin pub struct Mutex<T> {
30*935f40ecSlogin     /// 该Mutex保护的数据
31*935f40ecSlogin     data: UnsafeCell<T>,
32*935f40ecSlogin     /// Mutex内部的信息
33*935f40ecSlogin     inner: SpinLock<MutexInner>,
34*935f40ecSlogin }
35*935f40ecSlogin 
36*935f40ecSlogin /// @brief Mutex的守卫
37*935f40ecSlogin #[derive(Debug)]
38*935f40ecSlogin pub struct MutexGuard<'a, T: 'a> {
39*935f40ecSlogin     lock: &'a Mutex<T>,
40*935f40ecSlogin }
41*935f40ecSlogin 
42*935f40ecSlogin unsafe impl<T> Sync for Mutex<T> where T: Send {}
43*935f40ecSlogin 
44*935f40ecSlogin impl<T> Mutex<T> {
45*935f40ecSlogin     /// @brief 初始化一个新的Mutex对象
46*935f40ecSlogin     #[allow(dead_code)]
47*935f40ecSlogin     pub const fn new(value: T) -> Self {
48*935f40ecSlogin         return Self {
49*935f40ecSlogin             data: UnsafeCell::new(value),
50*935f40ecSlogin             inner: SpinLock::new(MutexInner {
51*935f40ecSlogin                 is_locked: false,
52*935f40ecSlogin                 wait_list: LinkedList::<&'static mut process_control_block>::new(),
53*935f40ecSlogin             }),
54*935f40ecSlogin         };
55*935f40ecSlogin     }
56*935f40ecSlogin 
57*935f40ecSlogin     /// @brief 对Mutex加锁
58*935f40ecSlogin     /// @return MutexGuard<T> 返回Mutex的守卫,您可以使用这个守卫来操作被保护的数据
59*935f40ecSlogin     #[inline(always)]
60*935f40ecSlogin     #[allow(dead_code)]
61*935f40ecSlogin     pub fn lock(&self) -> MutexGuard<T> {
62*935f40ecSlogin         loop {
63*935f40ecSlogin             let mut inner: SpinLockGuard<MutexInner> = self.inner.lock();
64*935f40ecSlogin             // 当前mutex已经上锁
65*935f40ecSlogin             if inner.is_locked {
66*935f40ecSlogin                 // 检查当前进程是否处于等待队列中,如果不在,就加到等待队列内
67*935f40ecSlogin                 if self.check_pid_in_wait_list(&inner, current_pcb().pid) == false {
68*935f40ecSlogin                     inner.wait_list.push_back(current_pcb());
69*935f40ecSlogin                 }
70*935f40ecSlogin 
71*935f40ecSlogin                 // 加到等待唤醒的队列,然后睡眠
72*935f40ecSlogin                 drop(inner);
73*935f40ecSlogin                 self.__sleep();
74*935f40ecSlogin             } else {
75*935f40ecSlogin                 // 加锁成功
76*935f40ecSlogin                 inner.is_locked = true;
77*935f40ecSlogin                 drop(inner);
78*935f40ecSlogin                 break;
79*935f40ecSlogin             }
80*935f40ecSlogin         }
81*935f40ecSlogin 
82*935f40ecSlogin         // 加锁成功,返回一个守卫
83*935f40ecSlogin         return MutexGuard { lock: self };
84*935f40ecSlogin     }
85*935f40ecSlogin 
86*935f40ecSlogin     /// @brief 尝试对Mutex加锁。如果加锁失败,不会将当前进程加入等待队列。
87*935f40ecSlogin     /// @return Ok 加锁成功,返回Mutex的守卫
88*935f40ecSlogin     /// @return Err 如果Mutex当前已经上锁,则返回Err.
89*935f40ecSlogin     #[inline(always)]
90*935f40ecSlogin     #[allow(dead_code)]
91*935f40ecSlogin     pub fn try_lock(&self) -> Result<MutexGuard<T>, i32> {
92*935f40ecSlogin         let mut inner = self.inner.lock();
93*935f40ecSlogin 
94*935f40ecSlogin         // 如果当前mutex已经上锁,则失败
95*935f40ecSlogin         if inner.is_locked {
96*935f40ecSlogin             return Err(-(EBUSY as i32));
97*935f40ecSlogin         } else {
98*935f40ecSlogin             // 加锁成功
99*935f40ecSlogin             inner.is_locked = true;
100*935f40ecSlogin             return Ok(MutexGuard { lock: self });
101*935f40ecSlogin         }
102*935f40ecSlogin     }
103*935f40ecSlogin 
104*935f40ecSlogin     /// @brief Mutex内部的睡眠函数
105*935f40ecSlogin     fn __sleep(&self) {
106*935f40ecSlogin         current_pcb().state &= !(PROC_RUNNING as u64);
107*935f40ecSlogin         current_pcb().state |= PROC_INTERRUPTIBLE as u64;
108*935f40ecSlogin         sched();
109*935f40ecSlogin     }
110*935f40ecSlogin 
111*935f40ecSlogin     /// @brief 放锁。
112*935f40ecSlogin     ///
113*935f40ecSlogin     /// 本函数只能是私有的,且只能被守卫的drop方法调用,否则将无法保证并发安全。
114*935f40ecSlogin     fn unlock(&self) {
115*935f40ecSlogin         let mut inner: SpinLockGuard<MutexInner> = self.inner.lock();
116*935f40ecSlogin         // 当前mutex一定是已经加锁的状态
117*935f40ecSlogin         assert!(inner.is_locked);
118*935f40ecSlogin         // 标记mutex已经解锁
119*935f40ecSlogin         inner.is_locked = false;
120*935f40ecSlogin         if inner.wait_list.is_empty() {
121*935f40ecSlogin             return;
122*935f40ecSlogin         }
123*935f40ecSlogin 
124*935f40ecSlogin         // wait_list不为空,则获取下一个要被唤醒的进程的pcb
125*935f40ecSlogin         let to_wakeup: &mut process_control_block = inner.wait_list.pop_front().unwrap();
126*935f40ecSlogin         drop(inner);
127*935f40ecSlogin 
128*935f40ecSlogin         unsafe {
129*935f40ecSlogin             process_wakeup(to_wakeup);
130*935f40ecSlogin         }
131*935f40ecSlogin     }
132*935f40ecSlogin 
133*935f40ecSlogin     /// @brief 检查进程是否在该mutex的等待队列内
134*935f40ecSlogin     #[inline]
135*935f40ecSlogin     fn check_pid_in_wait_list(&self, inner: &MutexInner, pid: pid_t) -> bool {
136*935f40ecSlogin         for p in inner.wait_list.iter() {
137*935f40ecSlogin             if p.pid == pid {
138*935f40ecSlogin                 // 在等待队列内
139*935f40ecSlogin                 return true;
140*935f40ecSlogin             }
141*935f40ecSlogin         }
142*935f40ecSlogin 
143*935f40ecSlogin         // 不在等待队列内
144*935f40ecSlogin         return false;
145*935f40ecSlogin     }
146*935f40ecSlogin }
147*935f40ecSlogin 
148*935f40ecSlogin /// 实现Deref trait,支持通过获取MutexGuard来获取临界区数据的不可变引用
149*935f40ecSlogin impl<T> Deref for MutexGuard<'_, T> {
150*935f40ecSlogin     type Target = T;
151*935f40ecSlogin 
152*935f40ecSlogin     fn deref(&self) -> &Self::Target {
153*935f40ecSlogin         return unsafe { &*self.lock.data.get() };
154*935f40ecSlogin     }
155*935f40ecSlogin }
156*935f40ecSlogin 
157*935f40ecSlogin /// 实现DerefMut trait,支持通过获取MutexGuard来获取临界区数据的可变引用
158*935f40ecSlogin impl<T> DerefMut for MutexGuard<'_, T> {
159*935f40ecSlogin     fn deref_mut(&mut self) -> &mut Self::Target {
160*935f40ecSlogin         return unsafe { &mut *self.lock.data.get() };
161*935f40ecSlogin     }
162*935f40ecSlogin }
163*935f40ecSlogin 
164*935f40ecSlogin /// @brief 为MutexGuard实现Drop方法,那么,一旦守卫的生命周期结束,就会自动释放自旋锁,避免了忘记放锁的情况
165*935f40ecSlogin impl<T> Drop for MutexGuard<'_, T> {
166*935f40ecSlogin     fn drop(&mut self) {
167*935f40ecSlogin         self.lock.unlock();
168*935f40ecSlogin     }
169*935f40ecSlogin }
170