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