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