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 { default() -> Self20 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 让当前进程在等待队列上进行等待,并且,允许被信号打断 sleep(&self)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函数闭包 sleep_with_func<F>(&self, f: F) where F: FnOnce(),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’,可能会导致一些未定义的行为。 sleep_without_schedule(&self)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 让当前进程在等待队列上进行等待,并且,不允许被信号打断 sleep_uninterruptible(&self)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加入队列后,解锁指定的自旋锁。 sleep_unlock_spinlock<T>(&self, to_unlock: SpinLockGuard<T>)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。 sleep_unlock_mutex<T>(&self, to_unlock: MutexGuard<T>)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加入队列后,解锁指定的自旋锁。 sleep_uninterruptible_unlock_spinlock<T>(&self, to_unlock: SpinLockGuard<T>)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。 sleep_uninterruptible_unlock_mutex<T>(&self, to_unlock: MutexGuard<T>)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 没有唤醒进程 wakeup(&self, state: u64) -> bool148 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,则唤醒这个进程。 wakeup_all(&self, state: u64)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 获得当前等待队列的大小 len(&self) -> usize195 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