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