xref: /DragonOS/kernel/src/libs/wait_queue.rs (revision a03c4f9dee5705207325c56629c0ccd219168f10)
1151251b5Slogin #![allow(dead_code)]
21496ba7bSLoGin use alloc::{collections::LinkedList, sync::Arc, vec::Vec};
3c8025a88Slogin 
4151251b5Slogin use crate::{
51496ba7bSLoGin     arch::{sched::sched, CurrentIrqArch},
6f678331aShanjiezhou     exception::InterruptArch,
71496ba7bSLoGin     kerror,
81496ba7bSLoGin     process::{ProcessControlBlock, ProcessManager, ProcessState},
9151251b5Slogin };
10151251b5Slogin 
11151251b5Slogin use super::{
12151251b5Slogin     mutex::MutexGuard,
13151251b5Slogin     spinlock::{SpinLock, SpinLockGuard},
14151251b5Slogin };
15c8025a88Slogin 
16151251b5Slogin #[derive(Debug)]
17151251b5Slogin struct InnerWaitQueue {
18151251b5Slogin     /// 等待队列的链表
191496ba7bSLoGin     wait_list: LinkedList<Arc<ProcessControlBlock>>,
20151251b5Slogin }
21151251b5Slogin 
22151251b5Slogin /// 被自旋锁保护的等待队列
23151251b5Slogin #[derive(Debug)]
24151251b5Slogin pub struct WaitQueue(SpinLock<InnerWaitQueue>);
25151251b5Slogin 
26151251b5Slogin impl WaitQueue {
27151251b5Slogin     pub const INIT: WaitQueue = WaitQueue(SpinLock::new(InnerWaitQueue::INIT));
28151251b5Slogin 
29151251b5Slogin     /// @brief 让当前进程在等待队列上进行等待,并且,允许被信号打断
30151251b5Slogin     pub fn sleep(&self) {
311496ba7bSLoGin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock_irqsave();
321496ba7bSLoGin         ProcessManager::mark_sleep(true).unwrap_or_else(|e| {
331496ba7bSLoGin             panic!("sleep error: {:?}", e);
341496ba7bSLoGin         });
351496ba7bSLoGin         guard.wait_list.push_back(ProcessManager::current_pcb());
36151251b5Slogin         drop(guard);
37151251b5Slogin         sched();
38151251b5Slogin     }
39151251b5Slogin 
40f678331aShanjiezhou     /// @brief 让当前进程在等待队列上进行等待,并且,在释放waitqueue的锁之前,执行f函数闭包
41f678331aShanjiezhou     pub fn sleep_with_func<F>(&self, f: F)
42f678331aShanjiezhou     where
43f678331aShanjiezhou         F: FnOnce(),
44f678331aShanjiezhou     {
45f678331aShanjiezhou         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
461496ba7bSLoGin         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
471496ba7bSLoGin         ProcessManager::mark_sleep(true).unwrap_or_else(|e| {
481496ba7bSLoGin             panic!("sleep error: {:?}", e);
491496ba7bSLoGin         });
501496ba7bSLoGin         drop(irq_guard);
511496ba7bSLoGin         guard.wait_list.push_back(ProcessManager::current_pcb());
52f678331aShanjiezhou         f();
53f678331aShanjiezhou         drop(guard);
54f678331aShanjiezhou         sched();
55f678331aShanjiezhou     }
56f678331aShanjiezhou 
57f678331aShanjiezhou     /// @brief 让当前进程在等待队列上进行等待. 但是,在释放waitqueue的锁之后,不会调用调度函数。
58f678331aShanjiezhou     /// 这样的设计,是为了让调用者可以在执行本函数之后,执行一些操作,然后再【手动调用调度函数】。
59f678331aShanjiezhou     ///
60f678331aShanjiezhou     /// 执行本函数前,需要确保处于【中断禁止】状态。
61f678331aShanjiezhou     ///
62f678331aShanjiezhou     /// 尽管sleep_with_func和sleep_without_schedule都可以实现这个功能,但是,sleep_with_func会在释放锁之前,执行f函数闭包。
63f678331aShanjiezhou     ///
64f678331aShanjiezhou     /// 考虑这样一个场景:
65f678331aShanjiezhou     /// 等待队列位于某个自旋锁保护的数据结构A中,我们希望在进程睡眠的同时,释放数据结构A的锁。
66f678331aShanjiezhou     /// 在这种情况下,如果使用sleep_with_func,所有权系统不会允许我们这么做。
67f678331aShanjiezhou     /// 因此,sleep_without_schedule的设计,正是为了解决这个问题。
68f678331aShanjiezhou     ///
69f678331aShanjiezhou     /// 由于sleep_without_schedule不会调用调度函数,因此,如果开发者忘记在执行本函数之后,手动调用调度函数,
70f678331aShanjiezhou     /// 由于时钟中断到来或者‘其他cpu kick了当前cpu’,可能会导致一些未定义的行为。
71f678331aShanjiezhou     pub unsafe fn sleep_without_schedule(&self) {
72f678331aShanjiezhou         // 安全检查:确保当前处于中断禁止状态
73f678331aShanjiezhou         assert!(CurrentIrqArch::is_irq_enabled() == false);
74f678331aShanjiezhou         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
751496ba7bSLoGin         ProcessManager::mark_sleep(true).unwrap_or_else(|e| {
761496ba7bSLoGin             panic!("sleep error: {:?}", e);
771496ba7bSLoGin         });
781496ba7bSLoGin         guard.wait_list.push_back(ProcessManager::current_pcb());
791496ba7bSLoGin         drop(guard);
801496ba7bSLoGin     }
811496ba7bSLoGin 
821496ba7bSLoGin     pub unsafe fn sleep_without_schedule_uninterruptible(&self) {
831496ba7bSLoGin         // 安全检查:确保当前处于中断禁止状态
841496ba7bSLoGin         assert!(CurrentIrqArch::is_irq_enabled() == false);
851496ba7bSLoGin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
861496ba7bSLoGin         ProcessManager::mark_sleep(false).unwrap_or_else(|e| {
871496ba7bSLoGin             panic!("sleep error: {:?}", e);
881496ba7bSLoGin         });
891496ba7bSLoGin         guard.wait_list.push_back(ProcessManager::current_pcb());
90f678331aShanjiezhou         drop(guard);
91f678331aShanjiezhou     }
92151251b5Slogin     /// @brief 让当前进程在等待队列上进行等待,并且,不允许被信号打断
93151251b5Slogin     pub fn sleep_uninterruptible(&self) {
94151251b5Slogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
951496ba7bSLoGin         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
961496ba7bSLoGin         ProcessManager::mark_sleep(false).unwrap_or_else(|e| {
971496ba7bSLoGin             panic!("sleep error: {:?}", e);
981496ba7bSLoGin         });
991496ba7bSLoGin         drop(irq_guard);
1001496ba7bSLoGin         guard.wait_list.push_back(ProcessManager::current_pcb());
101151251b5Slogin         drop(guard);
102151251b5Slogin         sched();
103151251b5Slogin     }
104151251b5Slogin 
105151251b5Slogin     /// @brief 让当前进程在等待队列上进行等待,并且,允许被信号打断。
106151251b5Slogin     /// 在当前进程的pcb加入队列后,解锁指定的自旋锁。
107151251b5Slogin     pub fn sleep_unlock_spinlock<T>(&self, to_unlock: SpinLockGuard<T>) {
108151251b5Slogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
1091496ba7bSLoGin         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
1101496ba7bSLoGin         ProcessManager::mark_sleep(true).unwrap_or_else(|e| {
1111496ba7bSLoGin             panic!("sleep error: {:?}", e);
1121496ba7bSLoGin         });
1131496ba7bSLoGin         drop(irq_guard);
1141496ba7bSLoGin         guard.wait_list.push_back(ProcessManager::current_pcb());
115151251b5Slogin         drop(to_unlock);
116151251b5Slogin         drop(guard);
117151251b5Slogin         sched();
118151251b5Slogin     }
119151251b5Slogin 
120151251b5Slogin     /// @brief 让当前进程在等待队列上进行等待,并且,允许被信号打断。
121151251b5Slogin     /// 在当前进程的pcb加入队列后,解锁指定的Mutex。
122151251b5Slogin     pub fn sleep_unlock_mutex<T>(&self, to_unlock: MutexGuard<T>) {
123151251b5Slogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
1241496ba7bSLoGin         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
1251496ba7bSLoGin         ProcessManager::mark_sleep(true).unwrap_or_else(|e| {
1261496ba7bSLoGin             panic!("sleep error: {:?}", e);
1271496ba7bSLoGin         });
1281496ba7bSLoGin         drop(irq_guard);
1291496ba7bSLoGin         guard.wait_list.push_back(ProcessManager::current_pcb());
130151251b5Slogin         drop(to_unlock);
131151251b5Slogin         drop(guard);
132151251b5Slogin         sched();
133151251b5Slogin     }
134151251b5Slogin 
135151251b5Slogin     /// @brief 让当前进程在等待队列上进行等待,并且,不允许被信号打断。
136151251b5Slogin     /// 在当前进程的pcb加入队列后,解锁指定的自旋锁。
137151251b5Slogin     pub fn sleep_uninterruptible_unlock_spinlock<T>(&self, to_unlock: SpinLockGuard<T>) {
138151251b5Slogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
1391496ba7bSLoGin         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
1401496ba7bSLoGin         ProcessManager::mark_sleep(false).unwrap_or_else(|e| {
1411496ba7bSLoGin             panic!("sleep error: {:?}", e);
1421496ba7bSLoGin         });
1431496ba7bSLoGin         drop(irq_guard);
1441496ba7bSLoGin         guard.wait_list.push_back(ProcessManager::current_pcb());
145151251b5Slogin         drop(to_unlock);
146151251b5Slogin         drop(guard);
147151251b5Slogin         sched();
148151251b5Slogin     }
149151251b5Slogin 
150151251b5Slogin     /// @brief 让当前进程在等待队列上进行等待,并且,不允许被信号打断。
151151251b5Slogin     /// 在当前进程的pcb加入队列后,解锁指定的Mutex。
152151251b5Slogin     pub fn sleep_uninterruptible_unlock_mutex<T>(&self, to_unlock: MutexGuard<T>) {
153151251b5Slogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
1541496ba7bSLoGin         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
1551496ba7bSLoGin         ProcessManager::mark_sleep(false).unwrap_or_else(|e| {
1561496ba7bSLoGin             panic!("sleep error: {:?}", e);
1571496ba7bSLoGin         });
1581496ba7bSLoGin         drop(irq_guard);
1591496ba7bSLoGin 
1601496ba7bSLoGin         guard.wait_list.push_back(ProcessManager::current_pcb());
1611496ba7bSLoGin 
162151251b5Slogin         drop(to_unlock);
163151251b5Slogin         drop(guard);
164151251b5Slogin         sched();
165151251b5Slogin     }
166151251b5Slogin 
167151251b5Slogin     /// @brief 唤醒在队列中等待的第一个进程。
168151251b5Slogin     /// 如果这个进程的state与给定的state进行and操作之后,结果不为0,则唤醒它。
169151251b5Slogin     ///
1701496ba7bSLoGin     /// @param state 用于判断的state,如果队列第一个进程与这个state相同,或者为None(表示不进行这个判断),则唤醒这个进程。
171151251b5Slogin     ///
172151251b5Slogin     /// @return true 成功唤醒进程
173151251b5Slogin     /// @return false 没有唤醒进程
1741496ba7bSLoGin     pub fn wakeup(&self, state: Option<ProcessState>) -> bool {
175151251b5Slogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
176151251b5Slogin         // 如果队列为空,则返回
177151251b5Slogin         if guard.wait_list.is_empty() {
178151251b5Slogin             return false;
179151251b5Slogin         }
180151251b5Slogin         // 如果队列头部的pcb的state与给定的state相与,结果不为0,则唤醒
1811496ba7bSLoGin         if let Some(state) = state {
1821496ba7bSLoGin             if guard.wait_list.front().unwrap().sched_info().state() != state {
183151251b5Slogin                 return false;
184151251b5Slogin             }
185151251b5Slogin         }
1861496ba7bSLoGin         let to_wakeup = guard.wait_list.pop_front().unwrap();
1871496ba7bSLoGin         let res = ProcessManager::wakeup(&to_wakeup).is_ok();
1881496ba7bSLoGin         return res;
1891496ba7bSLoGin     }
190151251b5Slogin 
191cde5492fSlogin     /// @brief 唤醒在队列中,符合条件的所有进程。
192cde5492fSlogin     ///
1931496ba7bSLoGin     /// @param state 用于判断的state,如果一个进程与这个state相同,或者为None(表示不进行这个判断),则唤醒这个进程。
1941496ba7bSLoGin     pub fn wakeup_all(&self, state: Option<ProcessState>) {
195cde5492fSlogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock_irqsave();
196cde5492fSlogin         // 如果队列为空,则返回
197cde5492fSlogin         if guard.wait_list.is_empty() {
198cde5492fSlogin             return;
199cde5492fSlogin         }
200cde5492fSlogin 
2011496ba7bSLoGin         let mut to_push_back: Vec<Arc<ProcessControlBlock>> = Vec::new();
202cde5492fSlogin         // 如果队列头部的pcb的state与给定的state相与,结果不为0,则唤醒
203cde5492fSlogin         while let Some(to_wakeup) = guard.wait_list.pop_front() {
204*a03c4f9dSLoGin             let mut wake = false;
2051496ba7bSLoGin             if let Some(state) = state {
2061496ba7bSLoGin                 if to_wakeup.sched_info().state() == state {
207*a03c4f9dSLoGin                     wake = true;
208*a03c4f9dSLoGin                 }
209*a03c4f9dSLoGin             } else {
210*a03c4f9dSLoGin                 wake = true;
211*a03c4f9dSLoGin             }
212*a03c4f9dSLoGin 
213*a03c4f9dSLoGin             if wake {
2141496ba7bSLoGin                 ProcessManager::wakeup(&to_wakeup).unwrap_or_else(|e| {
2151496ba7bSLoGin                     kerror!("wakeup pid: {:?} error: {:?}", to_wakeup.pid(), e);
2161496ba7bSLoGin                 });
2171496ba7bSLoGin                 continue;
218*a03c4f9dSLoGin             } else {
219cde5492fSlogin                 to_push_back.push(to_wakeup);
220cde5492fSlogin             }
221*a03c4f9dSLoGin         }
222*a03c4f9dSLoGin 
223cde5492fSlogin         for to_wakeup in to_push_back {
224cde5492fSlogin             guard.wait_list.push_back(to_wakeup);
225cde5492fSlogin         }
226cde5492fSlogin     }
227cde5492fSlogin 
228151251b5Slogin     /// @brief 获得当前等待队列的大小
229151251b5Slogin     pub fn len(&self) -> usize {
230151251b5Slogin         return self.0.lock().wait_list.len();
231151251b5Slogin     }
232151251b5Slogin }
233151251b5Slogin 
234151251b5Slogin impl InnerWaitQueue {
235151251b5Slogin     pub const INIT: InnerWaitQueue = InnerWaitQueue {
236151251b5Slogin         wait_list: LinkedList::new(),
237151251b5Slogin     };
238151251b5Slogin }
239