1 use core::{ptr::null_mut, sync::atomic::compiler_fence};
2 
3 use alloc::{boxed::Box, vec::Vec};
4 
5 use crate::{
6     arch::asm::current::current_pcb,
7     include::bindings::bindings::{
8         initial_proc_union, process_control_block, MAX_CPU_NUM, PF_NEED_SCHED, PROC_RUNNING,
9     },
10     kBUG,
11     libs::spinlock::RawSpinlock,
12     smp::core::smp_get_processor_id,
13 };
14 
15 use super::core::{sched_enqueue, Scheduler};
16 
17 /// 声明全局的cfs调度器实例
18 
19 pub static mut CFS_SCHEDULER_PTR: *mut SchedulerCFS = null_mut();
20 
21 /// @brief 获取cfs调度器实例的可变引用
22 #[inline]
__get_cfs_scheduler() -> &'static mut SchedulerCFS23 pub fn __get_cfs_scheduler() -> &'static mut SchedulerCFS {
24     return unsafe { CFS_SCHEDULER_PTR.as_mut().unwrap() };
25 }
26 
27 /// @brief 初始化cfs调度器
sched_cfs_init()28 pub unsafe fn sched_cfs_init() {
29     if CFS_SCHEDULER_PTR.is_null() {
30         CFS_SCHEDULER_PTR = Box::leak(Box::new(SchedulerCFS::new()));
31     } else {
32         kBUG!("Try to init CFS Scheduler twice.");
33         panic!("Try to init CFS Scheduler twice.");
34     }
35 }
36 
37 /// @brief CFS队列(per-cpu的)
38 #[derive(Debug)]
39 struct CFSQueue {
40     /// 当前cpu上执行的进程,剩余的时间片
41     cpu_exec_proc_jiffies: i64,
42     /// 队列的锁
43     lock: RawSpinlock,
44     /// 进程的队列
45     queue: Vec<&'static mut process_control_block>,
46     /// 当前核心的队列专属的IDLE进程的pcb
47     idle_pcb: *mut process_control_block,
48 }
49 
50 impl CFSQueue {
new(idle_pcb: *mut process_control_block) -> CFSQueue51     pub fn new(idle_pcb: *mut process_control_block) -> CFSQueue {
52         CFSQueue {
53             cpu_exec_proc_jiffies: 0,
54             lock: RawSpinlock::INIT,
55             queue: Vec::new(),
56             idle_pcb: idle_pcb,
57         }
58     }
59 
60     /// @brief 将进程按照虚拟运行时间的升序进行排列
61     /// todo: 换掉这个sort方法,因为它底层是归并很占内存,且时间复杂度为nlogn,(遍历然后插入的方法,时间复杂度最坏是n)
sort(&mut self)62     pub fn sort(&mut self) {
63         self.queue
64             .sort_by(|a, b| (*a).virtual_runtime.cmp(&(*b).virtual_runtime));
65     }
66 
67     /// @brief 将pcb加入队列
enqueue(&mut self, pcb: &'static mut process_control_block)68     pub fn enqueue(&mut self, pcb: &'static mut process_control_block) {
69         self.lock.lock();
70 
71         // 如果进程是IDLE进程,那么就不加入队列
72         if pcb.pid == 0 {
73             self.lock.unlock();
74             return;
75         }
76         self.queue.push(pcb);
77         self.sort();
78         self.lock.unlock();
79     }
80 
81     /// @brief 将pcb从调度队列中弹出,若队列为空,则返回IDLE进程的pcb
dequeue(&mut self) -> &'static mut process_control_block82     pub fn dequeue(&mut self) -> &'static mut process_control_block {
83         let res: &'static mut process_control_block;
84         self.lock.lock();
85         if self.queue.len() > 0 {
86             // 队列不为空,返回下一个要执行的pcb
87             res = self.queue.pop().unwrap();
88         } else {
89             // 如果队列为空,则返回IDLE进程的pcb
90             res = unsafe { self.idle_pcb.as_mut().unwrap() };
91         }
92         self.lock.unlock();
93         return res;
94     }
95 
96     /// @brief 获取cfs队列的最小运行时间
97     ///
98     /// @return Option<i64> 如果队列不为空,那么返回队列中,最小的虚拟运行时间;否则返回None
min_vruntime(&self) -> Option<i64>99     pub fn min_vruntime(&self) -> Option<i64> {
100         if !self.queue.is_empty() {
101             return Some(self.queue.first().unwrap().virtual_runtime);
102         } else {
103             return None;
104         }
105     }
106     /// 获取运行队列的长度
get_cfs_queue_size(&mut self) -> usize107     pub fn get_cfs_queue_size(&mut self) -> usize {
108         return self.queue.len();
109     }
110 }
111 
112 /// @brief CFS调度器类
113 pub struct SchedulerCFS {
114     cpu_queue: Vec<&'static mut CFSQueue>,
115 }
116 
117 impl SchedulerCFS {
new() -> SchedulerCFS118     pub fn new() -> SchedulerCFS {
119         // 暂时手动指定核心数目
120         // todo: 从cpu模块来获取核心的数目
121         let mut result = SchedulerCFS {
122             cpu_queue: Default::default(),
123         };
124 
125         // 为每个cpu核心创建队列
126         for _ in 0..MAX_CPU_NUM {
127             result
128                 .cpu_queue
129                 .push(Box::leak(Box::new(CFSQueue::new(null_mut()))));
130         }
131         // 设置cpu0的pcb
132         result.cpu_queue[0].idle_pcb = unsafe { &mut initial_proc_union.pcb };
133 
134         return result;
135     }
136 
137     /// @brief 更新这个cpu上,这个进程的可执行时间。
138     #[inline]
update_cpu_exec_proc_jiffies(_priority: i64, cfs_queue: &mut CFSQueue) -> &mut CFSQueue139     fn update_cpu_exec_proc_jiffies(_priority: i64, cfs_queue: &mut CFSQueue) -> &mut CFSQueue {
140         // todo: 引入调度周期以及所有进程的优先权进行计算,然后设置分配给进程的可执行时间
141         cfs_queue.cpu_exec_proc_jiffies = 10;
142 
143         return cfs_queue;
144     }
145 
146     /// @brief 时钟中断到来时,由sched的core模块中的函数,调用本函数,更新CFS进程的可执行时间
timer_update_jiffies(&mut self)147     pub fn timer_update_jiffies(&mut self) {
148         let current_cpu_queue: &mut CFSQueue = self.cpu_queue[current_pcb().cpu_id as usize];
149         // todo: 引入调度周期以及所有进程的优先权进行计算,然后设置进程的可执行时间
150 
151         // 更新进程的剩余可执行时间
152         current_cpu_queue.lock.lock();
153         current_cpu_queue.cpu_exec_proc_jiffies -= 1;
154         // 时间片耗尽,标记需要被调度
155         if current_cpu_queue.cpu_exec_proc_jiffies <= 0 {
156             current_pcb().flags |= PF_NEED_SCHED as u64;
157         }
158         current_cpu_queue.lock.unlock();
159 
160         // 更新当前进程的虚拟运行时间
161         current_pcb().virtual_runtime += 1;
162     }
163 
164     /// @brief 将进程加入cpu的cfs调度队列,并且重设其虚拟运行时间为当前队列的最小值
enqueue_reset_vruntime(&mut self, pcb: &'static mut process_control_block)165     pub fn enqueue_reset_vruntime(&mut self, pcb: &'static mut process_control_block) {
166         let cpu_queue = &mut self.cpu_queue[pcb.cpu_id as usize];
167         if cpu_queue.queue.len() > 0 {
168             pcb.virtual_runtime = cpu_queue.min_vruntime().unwrap();
169         }
170 
171         cpu_queue.enqueue(pcb);
172     }
173 
174     /// @brief 设置cpu的队列的IDLE进程的pcb
set_cpu_idle(&mut self, cpu_id: usize, pcb: *mut process_control_block)175     pub fn set_cpu_idle(&mut self, cpu_id: usize, pcb: *mut process_control_block) {
176         // kdebug!("set cpu idle: id={}", cpu_id);
177         self.cpu_queue[cpu_id].idle_pcb = pcb;
178     }
179     /// 获取某个cpu的运行队列中的进程数
get_cfs_queue_len(&mut self, cpu_id: u32) -> usize180     pub fn get_cfs_queue_len(&mut self, cpu_id: u32) -> usize {
181         return self.cpu_queue[cpu_id as usize].get_cfs_queue_size();
182     }
183 }
184 
185 impl Scheduler for SchedulerCFS {
186     /// @brief 在当前cpu上进行调度。
187     /// 请注意,进入该函数之前,需要关中断
sched(&mut self) -> Option<&'static mut process_control_block>188     fn sched(&mut self) -> Option<&'static mut process_control_block> {
189         current_pcb().flags &= !(PF_NEED_SCHED as u64);
190         let current_cpu_id = smp_get_processor_id() as usize;
191 
192         let current_cpu_queue: &mut CFSQueue = self.cpu_queue[current_cpu_id];
193         let proc: &'static mut process_control_block = current_cpu_queue.dequeue();
194         compiler_fence(core::sync::atomic::Ordering::SeqCst);
195         // 如果当前不是running态,或者当前进程的虚拟运行时间大于等于下一个进程的,那就需要切换。
196         if (current_pcb().state & (PROC_RUNNING as u64)) == 0
197             || current_pcb().virtual_runtime >= proc.virtual_runtime
198         {
199             compiler_fence(core::sync::atomic::Ordering::SeqCst);
200             // 本次切换由于时间片到期引发,则再次加入就绪队列,否则交由其它功能模块进行管理
201             if current_pcb().state & (PROC_RUNNING as u64) != 0 {
202                 sched_enqueue(current_pcb(), false);
203                 compiler_fence(core::sync::atomic::Ordering::SeqCst);
204             }
205 
206             compiler_fence(core::sync::atomic::Ordering::SeqCst);
207             // 设置进程可以执行的时间
208             if current_cpu_queue.cpu_exec_proc_jiffies <= 0 {
209                 SchedulerCFS::update_cpu_exec_proc_jiffies(proc.priority, current_cpu_queue);
210             }
211 
212             compiler_fence(core::sync::atomic::Ordering::SeqCst);
213 
214             return Some(proc);
215         } else {
216             // 不进行切换
217 
218             // 设置进程可以执行的时间
219             compiler_fence(core::sync::atomic::Ordering::SeqCst);
220             if current_cpu_queue.cpu_exec_proc_jiffies <= 0 {
221                 SchedulerCFS::update_cpu_exec_proc_jiffies(proc.priority, current_cpu_queue);
222             }
223 
224             compiler_fence(core::sync::atomic::Ordering::SeqCst);
225             sched_enqueue(proc, false);
226             compiler_fence(core::sync::atomic::Ordering::SeqCst);
227         }
228         compiler_fence(core::sync::atomic::Ordering::SeqCst);
229         return None;
230     }
231 
enqueue(&mut self, pcb: &'static mut process_control_block)232     fn enqueue(&mut self, pcb: &'static mut process_control_block) {
233         let cpu_queue = &mut self.cpu_queue[pcb.cpu_id as usize];
234         cpu_queue.enqueue(pcb);
235     }
236 }
237