xref: /DragonOS/kernel/src/libs/wait_queue.rs (revision 2f6f547ae05c19871138e558ba6943ff07f4c68c)
1151251b5Slogin #![allow(dead_code)]
2*2f6f547aSGnoCiYeH use core::intrinsics::unlikely;
3*2f6f547aSGnoCiYeH 
41496ba7bSLoGin use alloc::{collections::LinkedList, sync::Arc, vec::Vec};
5c8025a88Slogin 
6151251b5Slogin use crate::{
71496ba7bSLoGin     arch::{sched::sched, CurrentIrqArch},
8f678331aShanjiezhou     exception::InterruptArch,
91496ba7bSLoGin     kerror,
101496ba7bSLoGin     process::{ProcessControlBlock, ProcessManager, ProcessState},
11151251b5Slogin };
12151251b5Slogin 
13151251b5Slogin use super::{
14151251b5Slogin     mutex::MutexGuard,
15151251b5Slogin     spinlock::{SpinLock, SpinLockGuard},
16151251b5Slogin };
17c8025a88Slogin 
18151251b5Slogin #[derive(Debug)]
19151251b5Slogin struct InnerWaitQueue {
20151251b5Slogin     /// 等待队列的链表
211496ba7bSLoGin     wait_list: LinkedList<Arc<ProcessControlBlock>>,
22151251b5Slogin }
23151251b5Slogin 
24151251b5Slogin /// 被自旋锁保护的等待队列
25151251b5Slogin #[derive(Debug)]
26151251b5Slogin pub struct WaitQueue(SpinLock<InnerWaitQueue>);
27151251b5Slogin 
28151251b5Slogin impl WaitQueue {
29151251b5Slogin     pub const INIT: WaitQueue = WaitQueue(SpinLock::new(InnerWaitQueue::INIT));
30151251b5Slogin 
31*2f6f547aSGnoCiYeH     fn before_sleep_check(&self, max_preempt: usize) {
32*2f6f547aSGnoCiYeH         let pcb = ProcessManager::current_pcb();
33*2f6f547aSGnoCiYeH         if unlikely(pcb.preempt_count() > max_preempt) {
34*2f6f547aSGnoCiYeH             kwarn!(
35*2f6f547aSGnoCiYeH                 "Process {:?}: Try to sleep when preempt count is {}",
36*2f6f547aSGnoCiYeH                 pcb.pid(),
37*2f6f547aSGnoCiYeH                 pcb.preempt_count()
38*2f6f547aSGnoCiYeH             );
39*2f6f547aSGnoCiYeH         }
40*2f6f547aSGnoCiYeH     }
41*2f6f547aSGnoCiYeH 
42151251b5Slogin     /// @brief 让当前进程在等待队列上进行等待,并且,允许被信号打断
43151251b5Slogin     pub fn sleep(&self) {
44*2f6f547aSGnoCiYeH         self.before_sleep_check(0);
451496ba7bSLoGin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock_irqsave();
461496ba7bSLoGin         ProcessManager::mark_sleep(true).unwrap_or_else(|e| {
471496ba7bSLoGin             panic!("sleep error: {:?}", e);
481496ba7bSLoGin         });
491496ba7bSLoGin         guard.wait_list.push_back(ProcessManager::current_pcb());
50151251b5Slogin         drop(guard);
51151251b5Slogin         sched();
52151251b5Slogin     }
53151251b5Slogin 
54f678331aShanjiezhou     /// @brief 让当前进程在等待队列上进行等待,并且,在释放waitqueue的锁之前,执行f函数闭包
55f678331aShanjiezhou     pub fn sleep_with_func<F>(&self, f: F)
56f678331aShanjiezhou     where
57f678331aShanjiezhou         F: FnOnce(),
58f678331aShanjiezhou     {
59*2f6f547aSGnoCiYeH         self.before_sleep_check(0);
60f678331aShanjiezhou         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
611496ba7bSLoGin         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
621496ba7bSLoGin         ProcessManager::mark_sleep(true).unwrap_or_else(|e| {
631496ba7bSLoGin             panic!("sleep error: {:?}", e);
641496ba7bSLoGin         });
651496ba7bSLoGin         drop(irq_guard);
661496ba7bSLoGin         guard.wait_list.push_back(ProcessManager::current_pcb());
67f678331aShanjiezhou         f();
68*2f6f547aSGnoCiYeH 
69f678331aShanjiezhou         drop(guard);
70f678331aShanjiezhou         sched();
71f678331aShanjiezhou     }
72f678331aShanjiezhou 
73f678331aShanjiezhou     /// @brief 让当前进程在等待队列上进行等待. 但是,在释放waitqueue的锁之后,不会调用调度函数。
74f678331aShanjiezhou     /// 这样的设计,是为了让调用者可以在执行本函数之后,执行一些操作,然后再【手动调用调度函数】。
75f678331aShanjiezhou     ///
76f678331aShanjiezhou     /// 执行本函数前,需要确保处于【中断禁止】状态。
77f678331aShanjiezhou     ///
78f678331aShanjiezhou     /// 尽管sleep_with_func和sleep_without_schedule都可以实现这个功能,但是,sleep_with_func会在释放锁之前,执行f函数闭包。
79f678331aShanjiezhou     ///
80f678331aShanjiezhou     /// 考虑这样一个场景:
81f678331aShanjiezhou     /// 等待队列位于某个自旋锁保护的数据结构A中,我们希望在进程睡眠的同时,释放数据结构A的锁。
82f678331aShanjiezhou     /// 在这种情况下,如果使用sleep_with_func,所有权系统不会允许我们这么做。
83f678331aShanjiezhou     /// 因此,sleep_without_schedule的设计,正是为了解决这个问题。
84f678331aShanjiezhou     ///
85f678331aShanjiezhou     /// 由于sleep_without_schedule不会调用调度函数,因此,如果开发者忘记在执行本函数之后,手动调用调度函数,
86f678331aShanjiezhou     /// 由于时钟中断到来或者‘其他cpu kick了当前cpu’,可能会导致一些未定义的行为。
87f678331aShanjiezhou     pub unsafe fn sleep_without_schedule(&self) {
88*2f6f547aSGnoCiYeH         self.before_sleep_check(0);
89f678331aShanjiezhou         // 安全检查:确保当前处于中断禁止状态
90f678331aShanjiezhou         assert!(CurrentIrqArch::is_irq_enabled() == false);
91f678331aShanjiezhou         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
921496ba7bSLoGin         ProcessManager::mark_sleep(true).unwrap_or_else(|e| {
931496ba7bSLoGin             panic!("sleep error: {:?}", e);
941496ba7bSLoGin         });
951496ba7bSLoGin         guard.wait_list.push_back(ProcessManager::current_pcb());
961496ba7bSLoGin         drop(guard);
971496ba7bSLoGin     }
981496ba7bSLoGin 
991496ba7bSLoGin     pub unsafe fn sleep_without_schedule_uninterruptible(&self) {
100*2f6f547aSGnoCiYeH         self.before_sleep_check(0);
1011496ba7bSLoGin         // 安全检查:确保当前处于中断禁止状态
1021496ba7bSLoGin         assert!(CurrentIrqArch::is_irq_enabled() == false);
1031496ba7bSLoGin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
1041496ba7bSLoGin         ProcessManager::mark_sleep(false).unwrap_or_else(|e| {
1051496ba7bSLoGin             panic!("sleep error: {:?}", e);
1061496ba7bSLoGin         });
1071496ba7bSLoGin         guard.wait_list.push_back(ProcessManager::current_pcb());
108f678331aShanjiezhou         drop(guard);
109f678331aShanjiezhou     }
110151251b5Slogin     /// @brief 让当前进程在等待队列上进行等待,并且,不允许被信号打断
111151251b5Slogin     pub fn sleep_uninterruptible(&self) {
112*2f6f547aSGnoCiYeH         self.before_sleep_check(0);
113151251b5Slogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
1141496ba7bSLoGin         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
1151496ba7bSLoGin         ProcessManager::mark_sleep(false).unwrap_or_else(|e| {
1161496ba7bSLoGin             panic!("sleep error: {:?}", e);
1171496ba7bSLoGin         });
1181496ba7bSLoGin         drop(irq_guard);
1191496ba7bSLoGin         guard.wait_list.push_back(ProcessManager::current_pcb());
120151251b5Slogin         drop(guard);
121151251b5Slogin         sched();
122151251b5Slogin     }
123151251b5Slogin 
124151251b5Slogin     /// @brief 让当前进程在等待队列上进行等待,并且,允许被信号打断。
125151251b5Slogin     /// 在当前进程的pcb加入队列后,解锁指定的自旋锁。
126151251b5Slogin     pub fn sleep_unlock_spinlock<T>(&self, to_unlock: SpinLockGuard<T>) {
127*2f6f547aSGnoCiYeH         self.before_sleep_check(1);
128151251b5Slogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
1291496ba7bSLoGin         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
1301496ba7bSLoGin         ProcessManager::mark_sleep(true).unwrap_or_else(|e| {
1311496ba7bSLoGin             panic!("sleep error: {:?}", e);
1321496ba7bSLoGin         });
1331496ba7bSLoGin         drop(irq_guard);
1341496ba7bSLoGin         guard.wait_list.push_back(ProcessManager::current_pcb());
135151251b5Slogin         drop(to_unlock);
136151251b5Slogin         drop(guard);
137151251b5Slogin         sched();
138151251b5Slogin     }
139151251b5Slogin 
140151251b5Slogin     /// @brief 让当前进程在等待队列上进行等待,并且,允许被信号打断。
141151251b5Slogin     /// 在当前进程的pcb加入队列后,解锁指定的Mutex。
142151251b5Slogin     pub fn sleep_unlock_mutex<T>(&self, to_unlock: MutexGuard<T>) {
143*2f6f547aSGnoCiYeH         self.before_sleep_check(1);
144151251b5Slogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
1451496ba7bSLoGin         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
1461496ba7bSLoGin         ProcessManager::mark_sleep(true).unwrap_or_else(|e| {
1471496ba7bSLoGin             panic!("sleep error: {:?}", e);
1481496ba7bSLoGin         });
1491496ba7bSLoGin         drop(irq_guard);
1501496ba7bSLoGin         guard.wait_list.push_back(ProcessManager::current_pcb());
151151251b5Slogin         drop(to_unlock);
152151251b5Slogin         drop(guard);
153151251b5Slogin         sched();
154151251b5Slogin     }
155151251b5Slogin 
156151251b5Slogin     /// @brief 让当前进程在等待队列上进行等待,并且,不允许被信号打断。
157151251b5Slogin     /// 在当前进程的pcb加入队列后,解锁指定的自旋锁。
158151251b5Slogin     pub fn sleep_uninterruptible_unlock_spinlock<T>(&self, to_unlock: SpinLockGuard<T>) {
159*2f6f547aSGnoCiYeH         self.before_sleep_check(1);
160151251b5Slogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
1611496ba7bSLoGin         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
1621496ba7bSLoGin         ProcessManager::mark_sleep(false).unwrap_or_else(|e| {
1631496ba7bSLoGin             panic!("sleep error: {:?}", e);
1641496ba7bSLoGin         });
1651496ba7bSLoGin         drop(irq_guard);
1661496ba7bSLoGin         guard.wait_list.push_back(ProcessManager::current_pcb());
167151251b5Slogin         drop(to_unlock);
168151251b5Slogin         drop(guard);
169151251b5Slogin         sched();
170151251b5Slogin     }
171151251b5Slogin 
172151251b5Slogin     /// @brief 让当前进程在等待队列上进行等待,并且,不允许被信号打断。
173151251b5Slogin     /// 在当前进程的pcb加入队列后,解锁指定的Mutex。
174151251b5Slogin     pub fn sleep_uninterruptible_unlock_mutex<T>(&self, to_unlock: MutexGuard<T>) {
175*2f6f547aSGnoCiYeH         self.before_sleep_check(1);
176151251b5Slogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
1771496ba7bSLoGin         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
1781496ba7bSLoGin         ProcessManager::mark_sleep(false).unwrap_or_else(|e| {
1791496ba7bSLoGin             panic!("sleep error: {:?}", e);
1801496ba7bSLoGin         });
1811496ba7bSLoGin         drop(irq_guard);
1821496ba7bSLoGin 
1831496ba7bSLoGin         guard.wait_list.push_back(ProcessManager::current_pcb());
1841496ba7bSLoGin 
185151251b5Slogin         drop(to_unlock);
186151251b5Slogin         drop(guard);
187151251b5Slogin         sched();
188151251b5Slogin     }
189151251b5Slogin 
190151251b5Slogin     /// @brief 唤醒在队列中等待的第一个进程。
191151251b5Slogin     /// 如果这个进程的state与给定的state进行and操作之后,结果不为0,则唤醒它。
192151251b5Slogin     ///
1931496ba7bSLoGin     /// @param state 用于判断的state,如果队列第一个进程与这个state相同,或者为None(表示不进行这个判断),则唤醒这个进程。
194151251b5Slogin     ///
195151251b5Slogin     /// @return true 成功唤醒进程
196151251b5Slogin     /// @return false 没有唤醒进程
1971496ba7bSLoGin     pub fn wakeup(&self, state: Option<ProcessState>) -> bool {
198151251b5Slogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock();
199151251b5Slogin         // 如果队列为空,则返回
200151251b5Slogin         if guard.wait_list.is_empty() {
201151251b5Slogin             return false;
202151251b5Slogin         }
203151251b5Slogin         // 如果队列头部的pcb的state与给定的state相与,结果不为0,则唤醒
2041496ba7bSLoGin         if let Some(state) = state {
2051496ba7bSLoGin             if guard.wait_list.front().unwrap().sched_info().state() != state {
206151251b5Slogin                 return false;
207151251b5Slogin             }
208151251b5Slogin         }
2091496ba7bSLoGin         let to_wakeup = guard.wait_list.pop_front().unwrap();
2101496ba7bSLoGin         let res = ProcessManager::wakeup(&to_wakeup).is_ok();
2111496ba7bSLoGin         return res;
2121496ba7bSLoGin     }
213151251b5Slogin 
214cde5492fSlogin     /// @brief 唤醒在队列中,符合条件的所有进程。
215cde5492fSlogin     ///
2161496ba7bSLoGin     /// @param state 用于判断的state,如果一个进程与这个state相同,或者为None(表示不进行这个判断),则唤醒这个进程。
2171496ba7bSLoGin     pub fn wakeup_all(&self, state: Option<ProcessState>) {
218cde5492fSlogin         let mut guard: SpinLockGuard<InnerWaitQueue> = self.0.lock_irqsave();
219cde5492fSlogin         // 如果队列为空,则返回
220cde5492fSlogin         if guard.wait_list.is_empty() {
221cde5492fSlogin             return;
222cde5492fSlogin         }
223cde5492fSlogin 
2241496ba7bSLoGin         let mut to_push_back: Vec<Arc<ProcessControlBlock>> = Vec::new();
225cde5492fSlogin         // 如果队列头部的pcb的state与给定的state相与,结果不为0,则唤醒
226cde5492fSlogin         while let Some(to_wakeup) = guard.wait_list.pop_front() {
227a03c4f9dSLoGin             let mut wake = false;
2281496ba7bSLoGin             if let Some(state) = state {
2291496ba7bSLoGin                 if to_wakeup.sched_info().state() == state {
230a03c4f9dSLoGin                     wake = true;
231a03c4f9dSLoGin                 }
232a03c4f9dSLoGin             } else {
233a03c4f9dSLoGin                 wake = true;
234a03c4f9dSLoGin             }
235a03c4f9dSLoGin 
236a03c4f9dSLoGin             if wake {
2371496ba7bSLoGin                 ProcessManager::wakeup(&to_wakeup).unwrap_or_else(|e| {
2381496ba7bSLoGin                     kerror!("wakeup pid: {:?} error: {:?}", to_wakeup.pid(), e);
2391496ba7bSLoGin                 });
2401496ba7bSLoGin                 continue;
241a03c4f9dSLoGin             } else {
242cde5492fSlogin                 to_push_back.push(to_wakeup);
243cde5492fSlogin             }
244a03c4f9dSLoGin         }
245a03c4f9dSLoGin 
246cde5492fSlogin         for to_wakeup in to_push_back {
247cde5492fSlogin             guard.wait_list.push_back(to_wakeup);
248cde5492fSlogin         }
249cde5492fSlogin     }
250cde5492fSlogin 
251151251b5Slogin     /// @brief 获得当前等待队列的大小
252151251b5Slogin     pub fn len(&self) -> usize {
253151251b5Slogin         return self.0.lock().wait_list.len();
254151251b5Slogin     }
255151251b5Slogin }
256151251b5Slogin 
257151251b5Slogin impl InnerWaitQueue {
258151251b5Slogin     pub const INIT: InnerWaitQueue = InnerWaitQueue {
259151251b5Slogin         wait_list: LinkedList::new(),
260151251b5Slogin     };
261151251b5Slogin }
262