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, MAX_CPU_NUM, PF_NEED_MIGRATE, PROC_RUNNING, SCHED_FIFO,
12         SCHED_NORMAL, SCHED_RR,
13     },
14     process::process::process_cpu,
15     syscall::SystemError,
16 };
17 
18 use super::cfs::{sched_cfs_init, SchedulerCFS, __get_cfs_scheduler};
19 use super::rt::{sched_rt_init, SchedulerRT, __get_rt_scheduler};
20 
21 /// @brief 获取指定的cpu上正在执行的进程的pcb
22 #[inline]
cpu_executing(cpu_id: u32) -> &'static mut process_control_block23 pub fn cpu_executing(cpu_id: u32) -> &'static mut process_control_block {
24     // todo: 引入per_cpu之后,该函数真正执行“返回指定的cpu上正在执行的pcb”的功能
25 
26     if cpu_id == process_cpu(current_pcb()) {
27         return current_pcb();
28     } else {
29         todo!()
30     }
31 }
32 // 获取某个cpu的负载情况,返回当前负载,cpu_id 是获取负载的cpu的id
33 // TODO:将获取负载情况调整为最近一段时间运行进程的数量
get_cpu_loads(cpu_id: u32) -> u3234 pub fn get_cpu_loads(cpu_id: u32) -> u32 {
35     let cfs_scheduler = __get_cfs_scheduler();
36     let rt_scheduler = __get_rt_scheduler();
37     let len_cfs = cfs_scheduler.get_cfs_queue_len(cpu_id);
38     let len_rt = rt_scheduler.rt_queue_len(cpu_id);
39     // let load_rt = rt_scheduler.get_load_list_len(cpu_id);
40     // kdebug!("this cpu_id {} is load rt {}", cpu_id, load_rt);
41 
42     return (len_rt + len_cfs) as u32;
43 }
44 // 负载均衡
loads_balance(pcb: &mut process_control_block)45 pub fn loads_balance(pcb: &mut process_control_block) {
46     // 对pcb的迁移情况进行调整
47     // 获取总的CPU数量
48     let cpu_num = unsafe { smp_get_total_cpu() };
49     // 获取当前负载最小的CPU的id
50     let mut min_loads_cpu_id = pcb.cpu_id;
51     let mut min_loads = get_cpu_loads(pcb.cpu_id);
52     for cpu_id in 0..cpu_num {
53         let tmp_cpu_loads = get_cpu_loads(cpu_id);
54         if min_loads - tmp_cpu_loads > 0 {
55             min_loads_cpu_id = cpu_id;
56             min_loads = tmp_cpu_loads;
57         }
58     }
59 
60     // 将当前pcb迁移到负载最小的CPU
61     // 如果当前pcb的PF_NEED_MIGRATE已经置位,则不进行迁移操作
62     if (min_loads_cpu_id != pcb.cpu_id) && (pcb.flags & (PF_NEED_MIGRATE as u64)) == 0 {
63         // sched_migrate_process(pcb, min_loads_cpu_id as usize);
64         pcb.flags |= PF_NEED_MIGRATE as u64;
65         pcb.migrate_to = min_loads_cpu_id;
66         // kdebug!("set migrating, pcb:{:?}", pcb);
67     }
68 }
69 /// @brief 具体的调度器应当实现的trait
70 pub trait Scheduler {
71     /// @brief 使用该调度器发起调度的时候,要调用的函数
sched(&mut self) -> Option<&'static mut process_control_block>72     fn sched(&mut self) -> Option<&'static mut process_control_block>;
73 
74     /// @brief 将pcb加入这个调度器的调度队列
enqueue(&mut self, pcb: &'static mut process_control_block)75     fn enqueue(&mut self, pcb: &'static mut process_control_block);
76 }
77 
__sched() -> Option<&'static mut process_control_block>78 fn __sched() -> Option<&'static mut process_control_block> {
79     compiler_fence(core::sync::atomic::Ordering::SeqCst);
80     let cfs_scheduler: &mut SchedulerCFS = __get_cfs_scheduler();
81     let rt_scheduler: &mut SchedulerRT = __get_rt_scheduler();
82     compiler_fence(core::sync::atomic::Ordering::SeqCst);
83 
84     let next: &'static mut process_control_block;
85     match rt_scheduler.pick_next_task_rt(current_pcb().cpu_id) {
86         Some(p) => {
87             next = p;
88             // kdebug!("next pcb is {}",next.pid);
89             // 将pick的进程放回原处
90             rt_scheduler.enqueue_front(next);
91 
92             return rt_scheduler.sched();
93         }
94         None => {
95             return cfs_scheduler.sched();
96         }
97     }
98 }
99 
100 /// @brief 将进程加入调度队列
101 ///
102 /// @param pcb 要被加入队列的pcb
103 /// @param reset_time 是否重置虚拟运行时间
104 #[allow(dead_code)]
105 #[no_mangle]
sched_enqueue(pcb: &'static mut process_control_block, mut reset_time: bool)106 pub extern "C" fn sched_enqueue(pcb: &'static mut process_control_block, mut reset_time: bool) {
107     compiler_fence(core::sync::atomic::Ordering::SeqCst);
108 
109     // 调度器不处理running位为0的进程
110     if pcb.state & (PROC_RUNNING as u64) == 0 {
111         return;
112     }
113     let cfs_scheduler = __get_cfs_scheduler();
114     let rt_scheduler = __get_rt_scheduler();
115 
116     // 除了IDLE以外的进程,都进行负载均衡
117     if pcb.pid > 0 {
118         loads_balance(pcb);
119     }
120     compiler_fence(core::sync::atomic::Ordering::SeqCst);
121 
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 SystemError::EPERM.to_posix_errno() as u64;
180     }
181     // 根据调度结果统一进行切换
182     let pcb = __sched();
183 
184     if pcb.is_some() {
185         switch_process(current_pcb(), pcb.unwrap());
186     }
187     sti();
188     return 0;
189 }
190 
191 #[allow(dead_code)]
192 #[no_mangle]
sched_set_cpu_idle(cpu_id: usize, pcb: *mut process_control_block)193 pub extern "C" fn sched_set_cpu_idle(cpu_id: usize, pcb: *mut process_control_block) {
194     __get_cfs_scheduler().set_cpu_idle(cpu_id, pcb);
195 }
196 
197 /// @brief 设置进程需要等待迁移到另一个cpu核心。
198 /// 当进程被重新加入队列时,将会更新其cpu_id,并加入正确的队列
199 ///
200 /// @return i32 成功返回0,否则返回posix错误码
201 #[allow(dead_code)]
202 #[no_mangle]
sched_migrate_process( pcb: &'static mut process_control_block, target: usize, ) -> i32203 pub extern "C" fn sched_migrate_process(
204     pcb: &'static mut process_control_block,
205     target: usize,
206 ) -> i32 {
207     if target > MAX_CPU_NUM.try_into().unwrap() {
208         // panic!("sched_migrate_process: target > MAX_CPU_NUM");
209         return SystemError::EINVAL.to_posix_errno();
210     }
211 
212     pcb.flags |= PF_NEED_MIGRATE as u64;
213     pcb.migrate_to = target as u32;
214     // kdebug!("pid:{} migrate to cpu:{}", pcb.pid, target);
215     return 0;
216 }
217