1 #include "cfs.h"
2 #include <common/kprint.h>
3 #include <driver/video/video.h>
4 #include <common/spinlock.h>
5 
6 struct sched_queue_t sched_cfs_ready_queue[MAX_CPU_NUM]; // 就绪队列
7 
8 /**
9  * @brief 从就绪队列中取出PCB
10  *
11  * @return struct process_control_block*
12  */
sched_cfs_dequeue()13 struct process_control_block *sched_cfs_dequeue()
14 {
15     if (list_empty(&sched_cfs_ready_queue[proc_current_cpu_id].proc_queue.list))
16     {
17         // kdebug("list empty, count=%d", sched_cfs_ready_queue[proc_current_cpu_id].count);
18         return &initial_proc_union.pcb;
19     }
20 
21     struct process_control_block *proc = container_of(list_next(&sched_cfs_ready_queue[proc_current_cpu_id].proc_queue.list), struct process_control_block, list);
22 
23     list_del(&proc->list);
24     --sched_cfs_ready_queue[proc_current_cpu_id].count;
25     return proc;
26 }
27 
28 /**
29  * @brief 将PCB加入就绪队列
30  *
31  * @param pcb
32  */
sched_cfs_enqueue(struct process_control_block * pcb)33 void sched_cfs_enqueue(struct process_control_block *pcb)
34 {
35     if (pcb == initial_proc[proc_current_cpu_id])
36         return;
37     struct process_control_block *proc = container_of(list_next(&sched_cfs_ready_queue[proc_current_cpu_id].proc_queue.list), struct process_control_block, list);
38     if ((list_empty(&sched_cfs_ready_queue[proc_current_cpu_id].proc_queue.list)) == 0)
39     {
40         while (proc->virtual_runtime < pcb->virtual_runtime)
41         {
42             proc = container_of(list_next(&proc->list), struct process_control_block, list);
43         }
44     }
45     list_append(&proc->list, &pcb->list);
46     ++sched_cfs_ready_queue[proc_current_cpu_id].count;
47 }
48 
49 /**
50  * @brief 调度函数
51  *
52  */
sched_cfs()53 void sched_cfs()
54 {
55 
56     cli();
57 
58     current_pcb->flags &= ~PF_NEED_SCHED;
59     // kdebug("current_pcb pid= %d", current_pcb->pid);
60     struct process_control_block *proc = sched_cfs_dequeue();
61     // kdebug("sched_cfs_ready_queue[proc_current_cpu_id].count = %d", sched_cfs_ready_queue[proc_current_cpu_id].count);
62     if (current_pcb->virtual_runtime >= proc->virtual_runtime || !(current_pcb->state & PROC_RUNNING)) // 当前进程运行时间大于了下一进程的运行时间,进行切换
63     {
64 
65         // kdebug("current_pcb->virtual_runtime = %d,proc->vt= %d", current_pcb->virtual_runtime, proc->virtual_runtime);
66         if (current_pcb->state & PROC_RUNNING) // 本次切换由于时间片到期引发,则再次加入就绪队列,否则交由其它功能模块进行管理
67             sched_cfs_enqueue(current_pcb);
68         // kdebug("proc->pid=%d, count=%d", proc->pid, sched_cfs_ready_queue[proc_current_cpu_id].count);
69         if (sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies <= 0)
70         {
71             switch (proc->priority)
72             {
73             case 0:
74             case 1:
75                 sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies = 4 / sched_cfs_ready_queue[proc_current_cpu_id].count;
76                 break;
77             case 2:
78             default:
79                 sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies = (4 / sched_cfs_ready_queue[proc_current_cpu_id].count) << 2;
80                 break;
81             }
82         }
83 
84         process_switch_mm(proc);
85 
86         switch_proc(current_pcb, proc);
87     }
88     else // 不进行切换
89     {
90         // kdebug("not switch.");
91         sched_cfs_enqueue(proc);
92 
93         if (sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies <= 0)
94         {
95             switch (proc->priority)
96             {
97             case 0:
98             case 1:
99                 sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies = 4 / sched_cfs_ready_queue[proc_current_cpu_id].count;
100                 break;
101             case 2:
102             default:
103 
104                 sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies = (4 / sched_cfs_ready_queue[proc_current_cpu_id].count) << 2;
105                 break;
106             }
107         }
108     }
109 
110     sti();
111 }
112 
113 /**
114  * @brief 当时钟中断到达时,更新时间片
115  *
116  */
sched_update_jiffies()117 void sched_update_jiffies()
118 {
119 
120     switch (current_pcb->priority)
121     {
122     case 0:
123     case 1:
124         --sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies;
125         ++current_pcb->virtual_runtime;
126         break;
127     case 2:
128     default:
129         sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies -= 2;
130         current_pcb->virtual_runtime += 2;
131         break;
132     }
133     // 时间片耗尽,标记可调度
134     if (sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies <= 0)
135         current_pcb->flags |= PF_NEED_SCHED;
136 }
137 
138 /**
139  * @brief 初始化CFS调度器
140  *
141  */
sched_cfs_init()142 void sched_cfs_init()
143 {
144     memset(&sched_cfs_ready_queue, 0, sizeof(struct sched_queue_t) * MAX_CPU_NUM);
145     for (int i = 0; i < MAX_CPU_NUM; ++i)
146     {
147 
148         list_init(&sched_cfs_ready_queue[i].proc_queue.list);
149         sched_cfs_ready_queue[i].count = 1; // 因为存在IDLE进程,因此为1
150         sched_cfs_ready_queue[i].cpu_exec_proc_jiffies = 5;
151         sched_cfs_ready_queue[i].proc_queue.virtual_runtime = 0x7fffffffffffffff;
152     }
153 }