cfs.rs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. use core::sync::atomic::compiler_fence;
  2. use alloc::{boxed::Box, sync::Arc, vec::Vec};
  3. use crate::{
  4. arch::CurrentIrqArch,
  5. exception::InterruptArch,
  6. kBUG,
  7. libs::{
  8. rbtree::RBTree,
  9. spinlock::{SpinLock, SpinLockGuard},
  10. },
  11. mm::percpu::PerCpu,
  12. process::{
  13. ProcessControlBlock, ProcessFlags, ProcessManager, ProcessSchedulerInfo, ProcessState,
  14. },
  15. smp::{core::smp_get_processor_id, cpu::ProcessorId},
  16. };
  17. use super::{
  18. core::{sched_enqueue, Scheduler},
  19. SchedPriority,
  20. };
  21. /// 声明全局的cfs调度器实例
  22. pub static mut CFS_SCHEDULER_PTR: Option<Box<SchedulerCFS>> = None;
  23. /// @brief 获取cfs调度器实例的可变引用
  24. #[inline]
  25. pub fn __get_cfs_scheduler() -> &'static mut SchedulerCFS {
  26. return unsafe { CFS_SCHEDULER_PTR.as_mut().unwrap() };
  27. }
  28. /// @brief 初始化cfs调度器
  29. pub unsafe fn sched_cfs_init() {
  30. if CFS_SCHEDULER_PTR.is_none() {
  31. CFS_SCHEDULER_PTR = Some(Box::new(SchedulerCFS::new()));
  32. } else {
  33. kBUG!("Try to init CFS Scheduler twice.");
  34. panic!("Try to init CFS Scheduler twice.");
  35. }
  36. }
  37. /// @brief CFS队列(per-cpu的)
  38. #[derive(Debug)]
  39. struct CFSQueue {
  40. /// 当前cpu上执行的进程剩余的时间片
  41. cpu_exec_proc_jiffies: i64,
  42. /// 自旋锁保护的队列
  43. locked_queue: SpinLock<RBTree<i64, Arc<ProcessControlBlock>>>,
  44. /// 当前核心的队列专属的IDLE进程的pcb
  45. idle_pcb: Arc<ProcessControlBlock>,
  46. }
  47. impl CFSQueue {
  48. pub fn new(idle_pcb: Arc<ProcessControlBlock>) -> CFSQueue {
  49. CFSQueue {
  50. cpu_exec_proc_jiffies: 0,
  51. locked_queue: SpinLock::new(RBTree::new()),
  52. idle_pcb,
  53. }
  54. }
  55. /// @brief 将pcb加入队列
  56. pub fn enqueue(&mut self, pcb: Arc<ProcessControlBlock>) {
  57. let mut queue = self.locked_queue.lock_irqsave();
  58. // 如果进程是IDLE进程,那么就不加入队列
  59. if pcb.pid().into() == 0 {
  60. return;
  61. }
  62. queue.insert(pcb.sched_info().virtual_runtime() as i64, pcb.clone());
  63. }
  64. /// @brief 将pcb从调度队列中弹出,若队列为空,则返回IDLE进程的pcb
  65. pub fn dequeue(&mut self) -> Arc<ProcessControlBlock> {
  66. let res: Arc<ProcessControlBlock>;
  67. let mut queue = self.locked_queue.lock_irqsave();
  68. if !queue.is_empty() {
  69. // 队列不为空,返回下一个要执行的pcb
  70. res = queue.pop_first().unwrap().1;
  71. } else {
  72. // 如果队列为空,则返回IDLE进程的pcb
  73. res = self.idle_pcb.clone();
  74. }
  75. return res;
  76. }
  77. /// @brief 获取cfs队列的最小运行时间
  78. ///
  79. /// @return Option<i64> 如果队列不为空,那么返回队列中,最小的虚拟运行时间;否则返回None
  80. pub fn min_vruntime(
  81. queue: &SpinLockGuard<RBTree<i64, Arc<ProcessControlBlock>>>,
  82. ) -> Option<i64> {
  83. if !queue.is_empty() {
  84. return Some(queue.get_first().unwrap().1.sched_info().virtual_runtime() as i64);
  85. } else {
  86. return None;
  87. }
  88. }
  89. /// 获取运行队列的长度
  90. #[allow(dead_code)]
  91. pub fn get_cfs_queue_size(
  92. queue: &SpinLockGuard<RBTree<i64, Arc<ProcessControlBlock>>>,
  93. ) -> usize {
  94. return queue.len();
  95. }
  96. }
  97. /// @brief CFS调度器类
  98. pub struct SchedulerCFS {
  99. cpu_queue: Vec<&'static mut CFSQueue>,
  100. }
  101. impl SchedulerCFS {
  102. pub fn new() -> SchedulerCFS {
  103. // 暂时手动指定核心数目
  104. // todo: 从cpu模块来获取核心的数目
  105. let mut result = SchedulerCFS {
  106. cpu_queue: Default::default(),
  107. };
  108. // 为每个cpu核心创建队列,进程重构后可以直接初始化Idle_pcb?
  109. for i in 0..PerCpu::MAX_CPU_NUM {
  110. let idle_pcb = ProcessManager::idle_pcb()[i as usize].clone();
  111. result
  112. .cpu_queue
  113. .push(Box::leak(Box::new(CFSQueue::new(idle_pcb))));
  114. }
  115. return result;
  116. }
  117. /// @brief 更新这个cpu上,这个进程的可执行时间。
  118. #[inline]
  119. fn update_cpu_exec_proc_jiffies(
  120. _priority: SchedPriority,
  121. cfs_queue: &mut CFSQueue,
  122. is_idle: bool,
  123. ) -> &mut CFSQueue {
  124. // todo: 引入调度周期以及所有进程的优先权进行计算,然后设置分配给进程的可执行时间
  125. if !is_idle {
  126. cfs_queue.cpu_exec_proc_jiffies = 10;
  127. } else {
  128. cfs_queue.cpu_exec_proc_jiffies = 0;
  129. }
  130. return cfs_queue;
  131. }
  132. /// @brief 时钟中断到来时,由sched的core模块中的函数,调用本函数,更新CFS进程的可执行时间
  133. pub fn timer_update_jiffies(&mut self, sched_info: &ProcessSchedulerInfo) {
  134. let current_cpu_queue: &mut CFSQueue =
  135. self.cpu_queue[smp_get_processor_id().data() as usize];
  136. // todo: 引入调度周期以及所有进程的优先权进行计算,然后设置进程的可执行时间
  137. let mut queue = None;
  138. for _ in 0..10 {
  139. if let Ok(q) = current_cpu_queue.locked_queue.try_lock_irqsave() {
  140. queue = Some(q);
  141. break;
  142. }
  143. }
  144. if queue.is_none() {
  145. return;
  146. }
  147. let queue = queue.unwrap();
  148. // 更新进程的剩余可执行时间
  149. current_cpu_queue.cpu_exec_proc_jiffies -= 1;
  150. // 时间片耗尽,标记需要被调度
  151. if current_cpu_queue.cpu_exec_proc_jiffies <= 0 {
  152. ProcessManager::current_pcb()
  153. .flags()
  154. .insert(ProcessFlags::NEED_SCHEDULE);
  155. }
  156. drop(queue);
  157. // 更新当前进程的虚拟运行时间
  158. sched_info.increase_virtual_runtime(1);
  159. }
  160. /// @brief 将进程加入cpu的cfs调度队列,并且重设其虚拟运行时间为当前队列的最小值
  161. pub fn enqueue_reset_vruntime(&mut self, pcb: Arc<ProcessControlBlock>) {
  162. let cpu_queue = &mut self.cpu_queue[pcb.sched_info().on_cpu().unwrap().data() as usize];
  163. let queue = cpu_queue.locked_queue.lock_irqsave();
  164. if queue.len() > 0 {
  165. pcb.sched_info()
  166. .set_virtual_runtime(CFSQueue::min_vruntime(&queue).unwrap_or(0) as isize)
  167. }
  168. drop(queue);
  169. cpu_queue.enqueue(pcb);
  170. }
  171. /// @brief 设置cpu的队列的IDLE进程的pcb
  172. #[allow(dead_code)]
  173. pub fn set_cpu_idle(&mut self, cpu_id: usize, pcb: Arc<ProcessControlBlock>) {
  174. // kdebug!("set cpu idle: id={}", cpu_id);
  175. self.cpu_queue[cpu_id].idle_pcb = pcb;
  176. }
  177. /// 获取某个cpu的运行队列中的进程数
  178. pub fn get_cfs_queue_len(&mut self, cpu_id: ProcessorId) -> usize {
  179. let queue = self.cpu_queue[cpu_id.data() as usize]
  180. .locked_queue
  181. .lock_irqsave();
  182. return CFSQueue::get_cfs_queue_size(&queue);
  183. }
  184. }
  185. impl Scheduler for SchedulerCFS {
  186. /// @brief 在当前cpu上进行调度。
  187. /// 请注意,进入该函数之前,需要关中断
  188. fn sched(&mut self) -> Option<Arc<ProcessControlBlock>> {
  189. assert!(!CurrentIrqArch::is_irq_enabled());
  190. ProcessManager::current_pcb()
  191. .flags()
  192. .remove(ProcessFlags::NEED_SCHEDULE);
  193. let current_cpu_id = smp_get_processor_id().data() as usize;
  194. let current_cpu_queue: &mut CFSQueue = self.cpu_queue[current_cpu_id];
  195. let proc: Arc<ProcessControlBlock> = current_cpu_queue.dequeue();
  196. compiler_fence(core::sync::atomic::Ordering::SeqCst);
  197. // 如果当前不是running态,或者当前进程的虚拟运行时间大于等于下一个进程的,那就需要切换。
  198. let state = ProcessManager::current_pcb()
  199. .sched_info()
  200. .inner_lock_read_irqsave()
  201. .state();
  202. if (state != ProcessState::Runnable)
  203. || (ProcessManager::current_pcb().sched_info().virtual_runtime()
  204. >= proc.sched_info().virtual_runtime())
  205. {
  206. compiler_fence(core::sync::atomic::Ordering::SeqCst);
  207. // 本次切换由于时间片到期引发,则再次加入就绪队列,否则交由其它功能模块进行管理
  208. if state == ProcessState::Runnable {
  209. sched_enqueue(ProcessManager::current_pcb(), false);
  210. compiler_fence(core::sync::atomic::Ordering::SeqCst);
  211. }
  212. compiler_fence(core::sync::atomic::Ordering::SeqCst);
  213. // 设置进程可以执行的时间
  214. if current_cpu_queue.cpu_exec_proc_jiffies <= 0 {
  215. SchedulerCFS::update_cpu_exec_proc_jiffies(
  216. proc.sched_info().priority(),
  217. current_cpu_queue,
  218. Arc::ptr_eq(&proc, &current_cpu_queue.idle_pcb),
  219. );
  220. }
  221. compiler_fence(core::sync::atomic::Ordering::SeqCst);
  222. return Some(proc);
  223. } else {
  224. // 不进行切换
  225. // 设置进程可以执行的时间
  226. compiler_fence(core::sync::atomic::Ordering::SeqCst);
  227. if current_cpu_queue.cpu_exec_proc_jiffies <= 0 {
  228. SchedulerCFS::update_cpu_exec_proc_jiffies(
  229. ProcessManager::current_pcb().sched_info().priority(),
  230. current_cpu_queue,
  231. Arc::ptr_eq(&proc, &current_cpu_queue.idle_pcb),
  232. );
  233. // kdebug!("cpu:{:?}",current_cpu_id);
  234. }
  235. compiler_fence(core::sync::atomic::Ordering::SeqCst);
  236. sched_enqueue(proc, false);
  237. compiler_fence(core::sync::atomic::Ordering::SeqCst);
  238. }
  239. compiler_fence(core::sync::atomic::Ordering::SeqCst);
  240. return None;
  241. }
  242. fn enqueue(&mut self, pcb: Arc<ProcessControlBlock>) {
  243. let cpu_queue = &mut self.cpu_queue[pcb.sched_info().on_cpu().unwrap().data() as usize];
  244. cpu_queue.enqueue(pcb);
  245. }
  246. }