xref: /DragonOS/kernel/src/libs/wait_queue.rs (revision 83ed0ebc293d5a10245089f627f52770fd5b9dd4)
1 #![allow(dead_code)]
2 use core::intrinsics::unlikely;
3 
4 use alloc::{collections::LinkedList, sync::Arc, vec::Vec};
5 
6 use crate::{
7     arch::{sched::sched, CurrentIrqArch},
8     exception::InterruptArch,
9     kerror,
10     process::{ProcessControlBlock, ProcessManager, ProcessState},
11 };
12 
13 use super::{
14     mutex::MutexGuard,
15     spinlock::{SpinLock, SpinLockGuard},
16 };
17 
18 #[derive(Debug)]
19 struct InnerWaitQueue {
20     /// 等待队列的链表
21     wait_list: LinkedList<Arc<ProcessControlBlock>>,
22 }
23 
24 /// 被自旋锁保护的等待队列
25 #[derive(Debug)]
26 pub struct WaitQueue(SpinLock<InnerWaitQueue>);
27 
28 impl WaitQueue {
29     pub const INIT: WaitQueue = WaitQueue(SpinLock::new(InnerWaitQueue::INIT));
30 
31     fn before_sleep_check(&self, max_preempt: usize) {
32         let pcb = ProcessManager::current_pcb();
33         if unlikely(pcb.preempt_count() > max_preempt) {
34             kwarn!(
35                 "Process {:?}: Try to sleep when preempt count is {}",
36                 pcb.pid(),
37                 pcb.preempt_count()
38             );
39         }
40     }
41 
42     /// @brief 让当前进程在等待队列上进行等待,并且,允许被信号打断
43     pub fn sleep(&self) {
44         self.before_sleep_check(0);
45         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock_irqsave();
46         ProcessManager::mark_sleep(true).unwrap_or_else(|e| {
47             panic!("sleep error: {:?}", e);
48         });
49         guard.wait_list.push_back(ProcessManager::current_pcb());
50         drop(guard);
51         sched();
52     }
53 
54     /// @brief 让当前进程在等待队列上进行等待,并且,在释放waitqueue的锁之前,执行f函数闭包
55     pub fn sleep_with_func<F>(&self, f: F)
56     where
57         F: FnOnce(),
58     {
59         self.before_sleep_check(0);
60         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
61         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
62         ProcessManager::mark_sleep(true).unwrap_or_else(|e| {
63             panic!("sleep error: {:?}", e);
64         });
65         drop(irq_guard);
66         guard.wait_list.push_back(ProcessManager::current_pcb());
67         f();
68 
69         drop(guard);
70         sched();
71     }
72 
73     /// @brief 让当前进程在等待队列上进行等待. 但是,在释放waitqueue的锁之后,不会调用调度函数。
74     /// 这样的设计,是为了让调用者可以在执行本函数之后,执行一些操作,然后再【手动调用调度函数】。
75     ///
76     /// 执行本函数前,需要确保处于【中断禁止】状态。
77     ///
78     /// 尽管sleep_with_func和sleep_without_schedule都可以实现这个功能,但是,sleep_with_func会在释放锁之前,执行f函数闭包。
79     ///
80     /// 考虑这样一个场景:
81     /// 等待队列位于某个自旋锁保护的数据结构A中,我们希望在进程睡眠的同时,释放数据结构A的锁。
82     /// 在这种情况下,如果使用sleep_with_func,所有权系统不会允许我们这么做。
83     /// 因此,sleep_without_schedule的设计,正是为了解决这个问题。
84     ///
85     /// 由于sleep_without_schedule不会调用调度函数,因此,如果开发者忘记在执行本函数之后,手动调用调度函数,
86     /// 由于时钟中断到来或者‘其他cpu kick了当前cpu’,可能会导致一些未定义的行为。
87     pub unsafe fn sleep_without_schedule(&self) {
88         self.before_sleep_check(0);
89         // 安全检查:确保当前处于中断禁止状态
90         assert!(CurrentIrqArch::is_irq_enabled() == false);
91         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
92         ProcessManager::mark_sleep(true).unwrap_or_else(|e| {
93             panic!("sleep error: {:?}", e);
94         });
95         guard.wait_list.push_back(ProcessManager::current_pcb());
96         drop(guard);
97     }
98 
99     pub unsafe fn sleep_without_schedule_uninterruptible(&self) {
100         self.before_sleep_check(0);
101         // 安全检查:确保当前处于中断禁止状态
102         assert!(CurrentIrqArch::is_irq_enabled() == false);
103         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
104         ProcessManager::mark_sleep(false).unwrap_or_else(|e| {
105             panic!("sleep error: {:?}", e);
106         });
107         guard.wait_list.push_back(ProcessManager::current_pcb());
108         drop(guard);
109     }
110     /// @brief 让当前进程在等待队列上进行等待,并且,不允许被信号打断
111     pub fn sleep_uninterruptible(&self) {
112         self.before_sleep_check(0);
113         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
114         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
115         ProcessManager::mark_sleep(false).unwrap_or_else(|e| {
116             panic!("sleep error: {:?}", e);
117         });
118         drop(irq_guard);
119         guard.wait_list.push_back(ProcessManager::current_pcb());
120         drop(guard);
121         sched();
122     }
123 
124     /// @brief 让当前进程在等待队列上进行等待,并且,允许被信号打断。
125     /// 在当前进程的pcb加入队列后,解锁指定的自旋锁。
126     pub fn sleep_unlock_spinlock<T>(&self, to_unlock: SpinLockGuard<T>) {
127         self.before_sleep_check(1);
128         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
129         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
130         ProcessManager::mark_sleep(true).unwrap_or_else(|e| {
131             panic!("sleep error: {:?}", e);
132         });
133         drop(irq_guard);
134         guard.wait_list.push_back(ProcessManager::current_pcb());
135         drop(to_unlock);
136         drop(guard);
137         sched();
138     }
139 
140     /// @brief 让当前进程在等待队列上进行等待,并且,允许被信号打断。
141     /// 在当前进程的pcb加入队列后,解锁指定的Mutex。
142     pub fn sleep_unlock_mutex<T>(&self, to_unlock: MutexGuard<T>) {
143         self.before_sleep_check(1);
144         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
145         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
146         ProcessManager::mark_sleep(true).unwrap_or_else(|e| {
147             panic!("sleep error: {:?}", e);
148         });
149         drop(irq_guard);
150         guard.wait_list.push_back(ProcessManager::current_pcb());
151         drop(to_unlock);
152         drop(guard);
153         sched();
154     }
155 
156     /// @brief 让当前进程在等待队列上进行等待,并且,不允许被信号打断。
157     /// 在当前进程的pcb加入队列后,解锁指定的自旋锁。
158     pub fn sleep_uninterruptible_unlock_spinlock<T>(&self, to_unlock: SpinLockGuard<T>) {
159         self.before_sleep_check(1);
160         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
161         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
162         ProcessManager::mark_sleep(false).unwrap_or_else(|e| {
163             panic!("sleep error: {:?}", e);
164         });
165         drop(irq_guard);
166         guard.wait_list.push_back(ProcessManager::current_pcb());
167         drop(to_unlock);
168         drop(guard);
169         sched();
170     }
171 
172     /// @brief 让当前进程在等待队列上进行等待,并且,不允许被信号打断。
173     /// 在当前进程的pcb加入队列后,解锁指定的Mutex。
174     pub fn sleep_uninterruptible_unlock_mutex<T>(&self, to_unlock: MutexGuard<T>) {
175         self.before_sleep_check(1);
176         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
177         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
178         ProcessManager::mark_sleep(false).unwrap_or_else(|e| {
179             panic!("sleep error: {:?}", e);
180         });
181         drop(irq_guard);
182 
183         guard.wait_list.push_back(ProcessManager::current_pcb());
184 
185         drop(to_unlock);
186         drop(guard);
187         sched();
188     }
189 
190     /// @brief 唤醒在队列中等待的第一个进程。
191     /// 如果这个进程的state与给定的state进行and操作之后,结果不为0,则唤醒它。
192     ///
193     /// @param state 用于判断的state,如果队列第一个进程与这个state相同,或者为None(表示不进行这个判断),则唤醒这个进程。
194     ///
195     /// @return true 成功唤醒进程
196     /// @return false 没有唤醒进程
197     pub fn wakeup(&self, state: Option<ProcessState>) -> bool {
198         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
199         // 如果队列为空,则返回
200         if guard.wait_list.is_empty() {
201             return false;
202         }
203         // 如果队列头部的pcb的state与给定的state相与,结果不为0,则唤醒
204         if let Some(state) = state {
205             if guard.wait_list.front().unwrap().sched_info().state() != state {
206                 return false;
207             }
208         }
209         let to_wakeup = guard.wait_list.pop_front().unwrap();
210         let res = ProcessManager::wakeup(&to_wakeup).is_ok();
211         return res;
212     }
213 
214     /// @brief 唤醒在队列中,符合条件的所有进程。
215     ///
216     /// @param state 用于判断的state,如果一个进程与这个state相同,或者为None(表示不进行这个判断),则唤醒这个进程。
217     pub fn wakeup_all(&self, state: Option<ProcessState>) {
218         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock_irqsave();
219         // 如果队列为空,则返回
220         if guard.wait_list.is_empty() {
221             return;
222         }
223 
224         let mut to_push_back: Vec<Arc<ProcessControlBlock>> = Vec::new();
225         // 如果队列头部的pcb的state与给定的state相与,结果不为0,则唤醒
226         while let Some(to_wakeup) = guard.wait_list.pop_front() {
227             let mut wake = false;
228             if let Some(state) = state {
229                 if to_wakeup.sched_info().state() == state {
230                     wake = true;
231                 }
232             } else {
233                 wake = true;
234             }
235 
236             if wake {
237                 ProcessManager::wakeup(&to_wakeup).unwrap_or_else(|e| {
238                     kerror!("wakeup pid: {:?} error: {:?}", to_wakeup.pid(), e);
239                 });
240                 continue;
241             } else {
242                 to_push_back.push(to_wakeup);
243             }
244         }
245 
246         for to_wakeup in to_push_back {
247             guard.wait_list.push_back(to_wakeup);
248         }
249     }
250 
251     /// @brief 获得当前等待队列的大小
252     pub fn len(&self) -> usize {
253         return self.0.lock().wait_list.len();
254     }
255 }
256 
257 impl InnerWaitQueue {
258     pub const INIT: InnerWaitQueue = InnerWaitQueue {
259         wait_list: LinkedList::new(),
260     };
261 }
262