xref: /DragonOS/kernel/src/libs/wait_queue.rs (revision f678331a3315b7847f08ab32b42d5bf49a9f3a6a)
1151251b5Slogin #![allow(dead_code)]
2cde5492fSlogin use alloc::{collections::LinkedList, vec::Vec};
3c8025a88Slogin 
4151251b5Slogin use crate::{
5*f678331aShanjiezhou     arch::{asm::current::current_pcb, sched::sched, CurrentIrqArch},
6*f678331aShanjiezhou     exception::InterruptArch,
7151251b5Slogin     include::bindings::bindings::{
8151251b5Slogin         process_control_block, process_wakeup, wait_queue_head_t, PROC_INTERRUPTIBLE,
9151251b5Slogin         PROC_UNINTERRUPTIBLE,
10151251b5Slogin     },
11151251b5Slogin };
12151251b5Slogin 
13151251b5Slogin use super::{
14151251b5Slogin     list::list_init,
15151251b5Slogin     mutex::MutexGuard,
16151251b5Slogin     spinlock::{SpinLock, SpinLockGuard},
17151251b5Slogin };
18c8025a88Slogin 
19c8025a88Slogin impl Default for wait_queue_head_t {
20c8025a88Slogin     fn default() -> Self {
2106b09f34Skong         let mut x = Self {
2206b09f34Skong             wait_list: Default::default(),
2306b09f34Skong             lock: Default::default(),
2406b09f34Skong         };
25c8025a88Slogin         list_init(&mut x.wait_list);
26c8025a88Slogin         return x;
27c8025a88Slogin     }
28c8025a88Slogin }
29151251b5Slogin 
30151251b5Slogin #[derive(Debug)]
31151251b5Slogin struct InnerWaitQueue {
32151251b5Slogin     /// 等待队列的链表
33151251b5Slogin     wait_list: LinkedList<&'static mut process_control_block>,
34151251b5Slogin }
35151251b5Slogin 
36151251b5Slogin /// 被自旋锁保护的等待队列
37151251b5Slogin #[derive(Debug)]
38151251b5Slogin pub struct WaitQueue(SpinLock<InnerWaitQueue>);
39151251b5Slogin 
40151251b5Slogin impl WaitQueue {
41151251b5Slogin     pub const INIT: WaitQueue = WaitQueue(SpinLock::new(InnerWaitQueue::INIT));
42151251b5Slogin 
43151251b5Slogin     /// @brief 让当前进程在等待队列上进行等待,并且,允许被信号打断
44151251b5Slogin     pub fn sleep(&self) {
45151251b5Slogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
46151251b5Slogin         current_pcb().state = PROC_INTERRUPTIBLE as u64;
47151251b5Slogin         guard.wait_list.push_back(current_pcb());
48151251b5Slogin         drop(guard);
49*f678331aShanjiezhou 
50151251b5Slogin         sched();
51151251b5Slogin     }
52151251b5Slogin 
53*f678331aShanjiezhou     /// @brief 让当前进程在等待队列上进行等待,并且,在释放waitqueue的锁之前,执行f函数闭包
54*f678331aShanjiezhou     pub fn sleep_with_func<F>(&self, f: F)
55*f678331aShanjiezhou     where
56*f678331aShanjiezhou         F: FnOnce(),
57*f678331aShanjiezhou     {
58*f678331aShanjiezhou         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
59*f678331aShanjiezhou         current_pcb().state = PROC_INTERRUPTIBLE as u64;
60*f678331aShanjiezhou         guard.wait_list.push_back(current_pcb());
61*f678331aShanjiezhou         f();
62*f678331aShanjiezhou         drop(guard);
63*f678331aShanjiezhou         sched();
64*f678331aShanjiezhou     }
65*f678331aShanjiezhou 
66*f678331aShanjiezhou     /// @brief 让当前进程在等待队列上进行等待. 但是,在释放waitqueue的锁之后,不会调用调度函数。
67*f678331aShanjiezhou     /// 这样的设计,是为了让调用者可以在执行本函数之后,执行一些操作,然后再【手动调用调度函数】。
68*f678331aShanjiezhou     ///
69*f678331aShanjiezhou     /// 执行本函数前,需要确保处于【中断禁止】状态。
70*f678331aShanjiezhou     ///
71*f678331aShanjiezhou     /// 尽管sleep_with_func和sleep_without_schedule都可以实现这个功能,但是,sleep_with_func会在释放锁之前,执行f函数闭包。
72*f678331aShanjiezhou     ///
73*f678331aShanjiezhou     /// 考虑这样一个场景:
74*f678331aShanjiezhou     /// 等待队列位于某个自旋锁保护的数据结构A中,我们希望在进程睡眠的同时,释放数据结构A的锁。
75*f678331aShanjiezhou     /// 在这种情况下,如果使用sleep_with_func,所有权系统不会允许我们这么做。
76*f678331aShanjiezhou     /// 因此,sleep_without_schedule的设计,正是为了解决这个问题。
77*f678331aShanjiezhou     ///
78*f678331aShanjiezhou     /// 由于sleep_without_schedule不会调用调度函数,因此,如果开发者忘记在执行本函数之后,手动调用调度函数,
79*f678331aShanjiezhou     /// 由于时钟中断到来或者‘其他cpu kick了当前cpu’,可能会导致一些未定义的行为。
80*f678331aShanjiezhou     pub unsafe fn sleep_without_schedule(&self) {
81*f678331aShanjiezhou         // 安全检查:确保当前处于中断禁止状态
82*f678331aShanjiezhou         assert!(CurrentIrqArch::is_irq_enabled() == false);
83*f678331aShanjiezhou         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
84*f678331aShanjiezhou         current_pcb().state = PROC_INTERRUPTIBLE as u64;
85*f678331aShanjiezhou         guard.wait_list.push_back(current_pcb());
86*f678331aShanjiezhou         drop(guard);
87*f678331aShanjiezhou     }
88151251b5Slogin     /// @brief 让当前进程在等待队列上进行等待,并且,不允许被信号打断
89151251b5Slogin     pub fn sleep_uninterruptible(&self) {
90151251b5Slogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
91151251b5Slogin         current_pcb().state = PROC_UNINTERRUPTIBLE as u64;
92151251b5Slogin         guard.wait_list.push_back(current_pcb());
93151251b5Slogin         drop(guard);
94151251b5Slogin         sched();
95151251b5Slogin     }
96151251b5Slogin 
97151251b5Slogin     /// @brief 让当前进程在等待队列上进行等待,并且,允许被信号打断。
98151251b5Slogin     /// 在当前进程的pcb加入队列后,解锁指定的自旋锁。
99151251b5Slogin     pub fn sleep_unlock_spinlock<T>(&self, to_unlock: SpinLockGuard<T>) {
100151251b5Slogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
101151251b5Slogin         current_pcb().state = PROC_INTERRUPTIBLE as u64;
102151251b5Slogin         guard.wait_list.push_back(current_pcb());
103151251b5Slogin         drop(to_unlock);
104151251b5Slogin         drop(guard);
105151251b5Slogin         sched();
106151251b5Slogin     }
107151251b5Slogin 
108151251b5Slogin     /// @brief 让当前进程在等待队列上进行等待,并且,允许被信号打断。
109151251b5Slogin     /// 在当前进程的pcb加入队列后,解锁指定的Mutex。
110151251b5Slogin     pub fn sleep_unlock_mutex<T>(&self, to_unlock: MutexGuard<T>) {
111151251b5Slogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
112151251b5Slogin         current_pcb().state = PROC_INTERRUPTIBLE as u64;
113151251b5Slogin         guard.wait_list.push_back(current_pcb());
114151251b5Slogin         drop(to_unlock);
115151251b5Slogin         drop(guard);
116151251b5Slogin         sched();
117151251b5Slogin     }
118151251b5Slogin 
119151251b5Slogin     /// @brief 让当前进程在等待队列上进行等待,并且,不允许被信号打断。
120151251b5Slogin     /// 在当前进程的pcb加入队列后,解锁指定的自旋锁。
121151251b5Slogin     pub fn sleep_uninterruptible_unlock_spinlock<T>(&self, to_unlock: SpinLockGuard<T>) {
122151251b5Slogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
123151251b5Slogin         current_pcb().state = PROC_UNINTERRUPTIBLE as u64;
124151251b5Slogin         guard.wait_list.push_back(current_pcb());
125151251b5Slogin         drop(to_unlock);
126151251b5Slogin         drop(guard);
127151251b5Slogin         sched();
128151251b5Slogin     }
129151251b5Slogin 
130151251b5Slogin     /// @brief 让当前进程在等待队列上进行等待,并且,不允许被信号打断。
131151251b5Slogin     /// 在当前进程的pcb加入队列后,解锁指定的Mutex。
132151251b5Slogin     pub fn sleep_uninterruptible_unlock_mutex<T>(&self, to_unlock: MutexGuard<T>) {
133151251b5Slogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
134151251b5Slogin         current_pcb().state = PROC_UNINTERRUPTIBLE as u64;
135151251b5Slogin         guard.wait_list.push_back(current_pcb());
136151251b5Slogin         drop(to_unlock);
137151251b5Slogin         drop(guard);
138151251b5Slogin         sched();
139151251b5Slogin     }
140151251b5Slogin 
141151251b5Slogin     /// @brief 唤醒在队列中等待的第一个进程。
142151251b5Slogin     /// 如果这个进程的state与给定的state进行and操作之后,结果不为0,则唤醒它。
143151251b5Slogin     ///
144151251b5Slogin     /// @param state 用于判断的state,如果队列中第一个进程的state与它进行and操作之后,结果不为0,则唤醒这个进程。
145151251b5Slogin     ///
146151251b5Slogin     /// @return true 成功唤醒进程
147151251b5Slogin     /// @return false 没有唤醒进程
148151251b5Slogin     pub fn wakeup(&self, state: u64) -> bool {
149151251b5Slogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
150151251b5Slogin         // 如果队列为空,则返回
151151251b5Slogin         if guard.wait_list.is_empty() {
152151251b5Slogin             return false;
153151251b5Slogin         }
154151251b5Slogin 
155151251b5Slogin         // 如果队列头部的pcb的state与给定的state相与,结果不为0,则唤醒
156151251b5Slogin         if (guard.wait_list.front().unwrap().state & state) != 0 {
157151251b5Slogin             let to_wakeup = guard.wait_list.pop_front().unwrap();
158151251b5Slogin             unsafe {
159151251b5Slogin                 process_wakeup(to_wakeup);
160151251b5Slogin             }
161151251b5Slogin             return true;
162151251b5Slogin         } else {
163151251b5Slogin             return false;
164151251b5Slogin         }
165151251b5Slogin     }
166151251b5Slogin 
167cde5492fSlogin     /// @brief 唤醒在队列中,符合条件的所有进程。
168cde5492fSlogin     ///
169cde5492fSlogin     /// @param state 用于判断的state,如果队列中第一个进程的state与它进行and操作之后,结果不为0,则唤醒这个进程。
170cde5492fSlogin     pub fn wakeup_all(&self, state: u64) {
171cde5492fSlogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock_irqsave();
172cde5492fSlogin         // 如果队列为空,则返回
173cde5492fSlogin         if guard.wait_list.is_empty() {
174cde5492fSlogin             return;
175cde5492fSlogin         }
176cde5492fSlogin 
177cde5492fSlogin         let mut to_push_back: Vec<&mut process_control_block> = Vec::new();
178cde5492fSlogin         // 如果队列头部的pcb的state与给定的state相与,结果不为0,则唤醒
179cde5492fSlogin         while let Some(to_wakeup) = guard.wait_list.pop_front() {
180cde5492fSlogin             if (to_wakeup.state & state) != 0 {
181cde5492fSlogin                 unsafe {
182cde5492fSlogin                     process_wakeup(to_wakeup);
183cde5492fSlogin                 }
184cde5492fSlogin             } else {
185cde5492fSlogin                 to_push_back.push(to_wakeup);
186cde5492fSlogin             }
187cde5492fSlogin         }
188cde5492fSlogin 
189cde5492fSlogin         for to_wakeup in to_push_back {
190cde5492fSlogin             guard.wait_list.push_back(to_wakeup);
191cde5492fSlogin         }
192cde5492fSlogin     }
193cde5492fSlogin 
194151251b5Slogin     /// @brief 获得当前等待队列的大小
195151251b5Slogin     pub fn len(&self) -> usize {
196151251b5Slogin         return self.0.lock().wait_list.len();
197151251b5Slogin     }
198151251b5Slogin }
199151251b5Slogin 
200151251b5Slogin impl InnerWaitQueue {
201151251b5Slogin     pub const INIT: InnerWaitQueue = InnerWaitQueue {
202151251b5Slogin         wait_list: LinkedList::new(),
203151251b5Slogin     };
204151251b5Slogin }
205