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