1 use core::sync::atomic::compiler_fence;
2
3 use crate::{
4 arch::asm::{current::current_pcb, ptrace::user_mode},
5 arch::{
6 context::switch_process,
7 interrupt::{cli, sti},
8 },
9 include::bindings::bindings::smp_get_total_cpu,
10 include::bindings::bindings::{
11 process_control_block, pt_regs, EINVAL, EPERM, MAX_CPU_NUM, PF_NEED_MIGRATE, PROC_RUNNING,
12 SCHED_FIFO, SCHED_NORMAL, SCHED_RR,
13 },
14 process::process::process_cpu,
15 };
16
17 use super::cfs::{sched_cfs_init, SchedulerCFS, __get_cfs_scheduler};
18 use super::rt::{sched_rt_init, SchedulerRT, __get_rt_scheduler};
19
20 /// @brief 获取指定的cpu上正在执行的进程的pcb
21 #[inline]
cpu_executing(cpu_id: u32) -> &'static mut process_control_block22 pub fn cpu_executing(cpu_id: u32) -> &'static mut process_control_block {
23 // todo: 引入per_cpu之后,该函数真正执行“返回指定的cpu上正在执行的pcb”的功能
24
25 if cpu_id == process_cpu(current_pcb()) {
26 return current_pcb();
27 } else {
28 todo!()
29 }
30 }
31 // 获取某个cpu的负载情况,返回当前负载,cpu_id 是获取负载的cpu的id
32 // TODO:将获取负载情况调整为最近一段时间运行进程的数量
get_cpu_loads(cpu_id: u32) -> u3233 pub fn get_cpu_loads(cpu_id: u32) -> u32 {
34 let cfs_scheduler = __get_cfs_scheduler();
35 let rt_scheduler = __get_rt_scheduler();
36 let len_cfs = cfs_scheduler.get_cfs_queue_len(cpu_id);
37 let len_rt = rt_scheduler.get_rt_queue_len(cpu_id);
38 // let load_rt = rt_scheduler.get_load_list_len(cpu_id);
39 // kdebug!("this cpu_id {} is load rt {}", cpu_id, load_rt);
40
41 return (len_rt + len_cfs) as u32;
42 }
43 // 负载均衡
loads_balance(pcb: &mut process_control_block)44 pub fn loads_balance(pcb: &mut process_control_block) {
45 // 对pcb的迁移情况进行调整
46 // 获取总的CPU数量
47 let cpu_num = unsafe { smp_get_total_cpu() };
48 // 获取当前负载最小的CPU的id
49 let mut min_loads_cpu_id = pcb.cpu_id;
50 let mut min_loads = get_cpu_loads(pcb.cpu_id);
51 for cpu_id in 0..cpu_num {
52 let tmp_cpu_loads = get_cpu_loads(cpu_id);
53 if min_loads - tmp_cpu_loads > 0 {
54 min_loads_cpu_id = cpu_id;
55 min_loads = tmp_cpu_loads;
56 }
57 }
58
59 // 将当前pcb迁移到负载最小的CPU
60 // 如果当前pcb的PF_NEED_MIGRATE已经置位,则不进行迁移操作
61 if (min_loads_cpu_id != pcb.cpu_id) && (pcb.flags & (PF_NEED_MIGRATE as u64)) == 0 {
62 // sched_migrate_process(pcb, min_loads_cpu_id as usize);
63 pcb.flags |= PF_NEED_MIGRATE as u64;
64 pcb.migrate_to = min_loads_cpu_id;
65 // kdebug!("set migrating, pcb:{:?}", pcb);
66 }
67 }
68 /// @brief 具体的调度器应当实现的trait
69 pub trait Scheduler {
70 /// @brief 使用该调度器发起调度的时候,要调用的函数
sched(&mut self) -> Option<&'static mut process_control_block>71 fn sched(&mut self) -> Option<&'static mut process_control_block>;
72
73 /// @brief 将pcb加入这个调度器的调度队列
enqueue(&mut self, pcb: &'static mut process_control_block)74 fn enqueue(&mut self, pcb: &'static mut process_control_block);
75 }
76
__sched() -> Option<&'static mut process_control_block>77 fn __sched() -> Option<&'static mut process_control_block> {
78 compiler_fence(core::sync::atomic::Ordering::SeqCst);
79 let cfs_scheduler: &mut SchedulerCFS = __get_cfs_scheduler();
80 let rt_scheduler: &mut SchedulerRT = __get_rt_scheduler();
81 compiler_fence(core::sync::atomic::Ordering::SeqCst);
82
83 let next: &'static mut process_control_block;
84 match rt_scheduler.pick_next_task_rt(current_pcb().cpu_id) {
85 Some(p) => {
86 next = p;
87 // kdebug!("next pcb is {}",next.pid);
88 // 将pick的进程放回原处
89 rt_scheduler.enqueue_front(next);
90
91 return rt_scheduler.sched();
92 }
93 None => {
94 return cfs_scheduler.sched();
95 }
96 }
97 }
98
99 /// @brief 将进程加入调度队列
100 ///
101 /// @param pcb 要被加入队列的pcb
102 /// @param reset_time 是否重置虚拟运行时间
103 #[allow(dead_code)]
104 #[no_mangle]
sched_enqueue(pcb: &'static mut process_control_block, mut reset_time: bool)105 pub extern "C" fn sched_enqueue(pcb: &'static mut process_control_block, mut reset_time: bool) {
106 compiler_fence(core::sync::atomic::Ordering::SeqCst);
107
108 // 调度器不处理running位为0的进程
109 if pcb.state & (PROC_RUNNING as u64) == 0 {
110 return;
111 }
112 let cfs_scheduler = __get_cfs_scheduler();
113 let rt_scheduler = __get_rt_scheduler();
114 // TODO 前几号进程不进行迁移,这里需要判断修改,当前的意思为了调试已经初始化完成的rt进程
115 // if pcb.pid > 4 && pcb.policy!=0{
116 if pcb.pid > 4 {
117 loads_balance(pcb);
118 }
119 compiler_fence(core::sync::atomic::Ordering::SeqCst);
120
121 compiler_fence(core::sync::atomic::Ordering::SeqCst);
122 if (pcb.flags & (PF_NEED_MIGRATE as u64)) != 0 {
123 // kdebug!("migrating pcb:{:?}", pcb);
124 pcb.flags &= !(PF_NEED_MIGRATE as u64);
125 pcb.cpu_id = pcb.migrate_to;
126 reset_time = true;
127 }
128 compiler_fence(core::sync::atomic::Ordering::SeqCst);
129
130 if pcb.policy == SCHED_NORMAL {
131 if reset_time {
132 cfs_scheduler.enqueue_reset_vruntime(pcb);
133 } else {
134 cfs_scheduler.enqueue(pcb);
135 }
136 } else if pcb.policy == SCHED_FIFO || pcb.policy == SCHED_RR {
137 rt_scheduler.enqueue(pcb);
138 } else {
139 panic!("This policy is not supported at this time");
140 }
141 }
142
143 /// @brief 初始化进程调度器模块
144 #[allow(dead_code)]
145 #[no_mangle]
sched_init()146 pub extern "C" fn sched_init() {
147 unsafe {
148 sched_cfs_init();
149 sched_rt_init();
150 }
151 }
152
153 /// @brief 当时钟中断到达时,更新时间片
154 /// 请注意,该函数只能被时钟中断处理程序调用
155 #[allow(dead_code)]
156 #[no_mangle]
sched_update_jiffies()157 pub extern "C" fn sched_update_jiffies() {
158 match current_pcb().policy {
159 SCHED_NORMAL => {
160 __get_cfs_scheduler().timer_update_jiffies();
161 }
162 SCHED_FIFO | SCHED_RR => {
163 current_pcb().rt_time_slice -= 1;
164 }
165 _ => {
166 todo!()
167 }
168 }
169 }
170
171 /// @brief 让系统立即运行调度器的系统调用
172 /// 请注意,该系统调用不能由ring3的程序发起
173 #[allow(dead_code)]
174 #[no_mangle]
sys_sched(regs: &'static mut pt_regs) -> u64175 pub extern "C" fn sys_sched(regs: &'static mut pt_regs) -> u64 {
176 cli();
177 // 进行权限校验,拒绝用户态发起调度
178 if user_mode(regs) {
179 return (-(EPERM as i64)) as u64;
180 }
181 // 根据调度结果统一进行切换
182 let pcb = __sched();
183 if pcb.is_some() {
184 switch_process(current_pcb(), pcb.unwrap());
185 }
186 sti();
187 return 0;
188 }
189
190 #[allow(dead_code)]
191 #[no_mangle]
sched_set_cpu_idle(cpu_id: usize, pcb: *mut process_control_block)192 pub extern "C" fn sched_set_cpu_idle(cpu_id: usize, pcb: *mut process_control_block) {
193 __get_cfs_scheduler().set_cpu_idle(cpu_id, pcb);
194 }
195
196 /// @brief 设置进程需要等待迁移到另一个cpu核心。
197 /// 当进程被重新加入队列时,将会更新其cpu_id,并加入正确的队列
198 ///
199 /// @return i32 成功返回0,否则返回posix错误码
200 #[allow(dead_code)]
201 #[no_mangle]
sched_migrate_process( pcb: &'static mut process_control_block, target: usize, ) -> i32202 pub extern "C" fn sched_migrate_process(
203 pcb: &'static mut process_control_block,
204 target: usize,
205 ) -> i32 {
206 if target > MAX_CPU_NUM.try_into().unwrap() {
207 // panic!("sched_migrate_process: target > MAX_CPU_NUM");
208 return -(EINVAL as i32);
209 }
210
211 pcb.flags |= PF_NEED_MIGRATE as u64;
212 pcb.migrate_to = target as u32;
213 // kdebug!("pid:{} migrate to cpu:{}", pcb.pid, target);
214 return 0;
215 }
216