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