SimpleKernel 1.17.0
Loading...
Searching...
No Matches
fifo_scheduler_test.cpp
Go to the documentation of this file.
1
5#include "fifo_scheduler.hpp"
6
7#include <cstdint>
8
9#include "system_test.h"
11#include "task_messages.hpp"
12
13namespace {
14
15auto test_fifo_basic_functionality() -> bool {
16 klog::Info("Running test_fifo_basic_functionality...");
17
18 FifoScheduler scheduler;
19
20 // 验证调度器名称
21 EXPECT_EQ(scheduler.name[0], 'F', "Scheduler name should start with F");
22
23 // 创建测试任务
24 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
25 task1.fsm.Receive(MsgSchedule{});
26
27 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
28 task2.fsm.Receive(MsgSchedule{});
29
30 TaskControlBlock task3("Task3", 3, nullptr, nullptr);
31 task3.fsm.Receive(MsgSchedule{});
32
33 // 测试空队列
34 EXPECT_TRUE(scheduler.IsEmpty(), "Scheduler should be empty initially");
35 EXPECT_EQ(scheduler.GetQueueSize(), 0,
36 "Queue size should be 0 for empty queue");
37 EXPECT_EQ(scheduler.PickNext(), nullptr,
38 "PickNext should return nullptr for empty queue");
39
40 // 加入任务
41 scheduler.Enqueue(&task1);
42 EXPECT_EQ(scheduler.GetQueueSize(), 1,
43 "Queue size should be 1 after enqueue");
44
45 scheduler.Enqueue(&task2);
46 scheduler.Enqueue(&task3);
47 EXPECT_EQ(scheduler.GetQueueSize(), 3,
48 "Queue size should be 3 after 3 enqueues");
49
50 // 验证 FIFO 顺序
51 auto* picked1 = scheduler.PickNext();
52 EXPECT_EQ(picked1, &task1, "First picked task should be task1");
53
54 auto* picked2 = scheduler.PickNext();
55 EXPECT_EQ(picked2, &task2, "Second picked task should be task2");
56
57 auto* picked3 = scheduler.PickNext();
58 EXPECT_EQ(picked3, &task3, "Third picked task should be task3");
59
60 EXPECT_EQ(scheduler.PickNext(), nullptr,
61 "PickNext should return nullptr after all tasks picked");
62
63 klog::Info("test_fifo_basic_functionality passed");
64 return true;
65}
66
67auto test_fifo_ordering() -> bool {
68 klog::Info("Running test_fifo_ordering...");
69
70 FifoScheduler scheduler;
71 constexpr size_t kTaskCount = 10;
72 TaskControlBlock* tasks[kTaskCount];
73
74 // 初始化任务
75 for (size_t i = 0; i < kTaskCount; ++i) {
76 tasks[i] = new TaskControlBlock("Task", 10, nullptr, nullptr);
77 tasks[i]->fsm.Receive(MsgSchedule{});
78 scheduler.Enqueue(tasks[i]);
79 }
80
81 EXPECT_EQ(scheduler.GetQueueSize(), kTaskCount,
82 "Queue size should match task count");
83
84 // 验证严格的 FIFO 顺序
85 for (size_t i = 0; i < kTaskCount; ++i) {
86 auto* picked = scheduler.PickNext();
87 EXPECT_NE(picked, nullptr, "Picked task should not be nullptr");
88 EXPECT_EQ(picked, tasks[i], "Task should be picked in FIFO order");
89 }
90
91 EXPECT_TRUE(scheduler.IsEmpty(), "Scheduler should be empty after all picks");
92
93 // 清理内存
94 for (size_t i = 0; i < kTaskCount; ++i) {
95 delete tasks[i];
96 }
97
98 klog::Info("test_fifo_ordering passed");
99 return true;
100}
101
102auto test_fifo_dequeue() -> bool {
103 klog::Info("Running test_fifo_dequeue...");
104
105 FifoScheduler scheduler;
106
107 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
108 task1.fsm.Receive(MsgSchedule{});
109 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
110 task2.fsm.Receive(MsgSchedule{});
111 TaskControlBlock task3("Task3", 3, nullptr, nullptr);
112 task3.fsm.Receive(MsgSchedule{});
113 TaskControlBlock task4("Task4", 4, nullptr, nullptr);
114 task4.fsm.Receive(MsgSchedule{});
115
116 scheduler.Enqueue(&task1);
117 scheduler.Enqueue(&task2);
118 scheduler.Enqueue(&task3);
119 scheduler.Enqueue(&task4);
120
121 EXPECT_EQ(scheduler.GetQueueSize(), 4, "Queue size should be 4");
122
123 // 移除中间任务
124 scheduler.Dequeue(&task2);
125 EXPECT_EQ(scheduler.GetQueueSize(), 3,
126 "Queue size should be 3 after dequeue");
127
128 // 移除队首任务
129 scheduler.Dequeue(&task1);
130 EXPECT_EQ(scheduler.GetQueueSize(), 2,
131 "Queue size should be 2 after dequeue");
132
133 // 验证剩余任务顺序
134 auto* picked1 = scheduler.PickNext();
135 EXPECT_EQ(picked1, &task3, "First remaining task should be task3");
136
137 auto* picked2 = scheduler.PickNext();
138 EXPECT_EQ(picked2, &task4, "Second remaining task should be task4");
139
140 EXPECT_TRUE(scheduler.IsEmpty(), "Scheduler should be empty");
141
142 klog::Info("test_fifo_dequeue passed");
143 return true;
144}
145
146auto test_fifo_statistics() -> bool {
147 klog::Info("Running test_fifo_statistics...");
148
149 FifoScheduler scheduler;
150
151 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
152 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
153
154 // 初始统计
155 auto stats = scheduler.GetStats();
156 EXPECT_EQ(stats.total_enqueues, 0, "Initial enqueues should be 0");
157 EXPECT_EQ(stats.total_dequeues, 0, "Initial dequeues should be 0");
158 EXPECT_EQ(stats.total_picks, 0, "Initial picks should be 0");
159 EXPECT_EQ(stats.total_preemptions, 0, "Initial preemptions should be 0");
160
161 // 测试入队统计
162 scheduler.Enqueue(&task1);
163 scheduler.Enqueue(&task2);
164 stats = scheduler.GetStats();
165 EXPECT_EQ(stats.total_enqueues, 2, "Enqueues should be 2");
166
167 // 测试选择统计
168 (void)scheduler.PickNext();
169 (void)scheduler.PickNext();
170 stats = scheduler.GetStats();
171 EXPECT_EQ(stats.total_picks, 2, "Picks should be 2");
172
173 // 测试出队统计
174 scheduler.Enqueue(&task1);
175 scheduler.Dequeue(&task1);
176 stats = scheduler.GetStats();
177 EXPECT_EQ(stats.total_dequeues, 1, "Dequeues should be 1");
178
179 // 测试抢占统计
180 scheduler.OnPreempted(&task1);
181 scheduler.OnPreempted(&task2);
182 stats = scheduler.GetStats();
183 EXPECT_EQ(stats.total_preemptions, 2, "Preemptions should be 2");
184
185 // 重置统计
186 scheduler.ResetStats();
187 stats = scheduler.GetStats();
188 EXPECT_EQ(stats.total_enqueues, 0, "Enqueues should be 0 after reset");
189 EXPECT_EQ(stats.total_dequeues, 0, "Dequeues should be 0 after reset");
190 EXPECT_EQ(stats.total_picks, 0, "Picks should be 0 after reset");
191 EXPECT_EQ(stats.total_preemptions, 0, "Preemptions should be 0 after reset");
192
193 klog::Info("test_fifo_statistics passed");
194 return true;
195}
196
197auto test_fifo_mixed_operations() -> bool {
198 klog::Info("Running test_fifo_mixed_operations...");
199
200 FifoScheduler scheduler;
201
202 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
203 task1.fsm.Receive(MsgSchedule{});
204 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
205 task2.fsm.Receive(MsgSchedule{});
206 TaskControlBlock task3("Task3", 3, nullptr, nullptr);
207 task3.fsm.Receive(MsgSchedule{});
208 TaskControlBlock task4("Task4", 4, nullptr, nullptr);
209 task4.fsm.Receive(MsgSchedule{});
210 TaskControlBlock task5("Task5", 5, nullptr, nullptr);
211 task5.fsm.Receive(MsgSchedule{});
212
213 // 复杂的混合操作序列
214 scheduler.Enqueue(&task1);
215 scheduler.Enqueue(&task2);
216 scheduler.Enqueue(&task3);
217
218 auto* picked1 = scheduler.PickNext();
219 EXPECT_EQ(picked1, &task1, "First pick should be task1");
220
221 scheduler.Enqueue(&task4);
222 scheduler.Dequeue(&task3);
223 scheduler.Enqueue(&task5);
224
225 // 现在队列应该是 [task2, task4, task5]
226 EXPECT_EQ(scheduler.GetQueueSize(), 3, "Queue size should be 3");
227
228 auto* picked2 = scheduler.PickNext();
229 EXPECT_EQ(picked2, &task2, "Second pick should be task2");
230
231 auto* picked3 = scheduler.PickNext();
232 EXPECT_EQ(picked3, &task4, "Third pick should be task4");
233
234 auto* picked4 = scheduler.PickNext();
235 EXPECT_EQ(picked4, &task5, "Fourth pick should be task5");
236
237 EXPECT_TRUE(scheduler.IsEmpty(), "Scheduler should be empty");
238
239 klog::Info("test_fifo_mixed_operations passed");
240 return true;
241}
242
243auto test_fifo_repeated_enqueue() -> bool {
244 klog::Info("Running test_fifo_repeated_enqueue...");
245
246 FifoScheduler scheduler;
247
248 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
249 task1.fsm.Receive(MsgSchedule{});
250
251 // 模拟任务多次时间片用完后重新入队
252 scheduler.Enqueue(&task1);
253 auto* picked1 = scheduler.PickNext();
254 EXPECT_EQ(picked1, &task1, "First pick should be task1");
255
256 scheduler.Enqueue(&task1);
257 auto* picked2 = scheduler.PickNext();
258 EXPECT_EQ(picked2, &task1, "Second pick should be task1");
259
260 scheduler.Enqueue(&task1);
261 auto* picked3 = scheduler.PickNext();
262 EXPECT_EQ(picked3, &task1, "Third pick should be task1");
263
264 EXPECT_TRUE(scheduler.IsEmpty(), "Scheduler should be empty");
265
266 klog::Info("test_fifo_repeated_enqueue passed");
267 return true;
268}
269
270auto test_fifo_hooks() -> bool {
271 klog::Info("Running test_fifo_hooks...");
272
273 FifoScheduler scheduler;
274
275 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
276 task1.fsm.Receive(MsgSchedule{});
277 task1.sched_info.priority = 5;
278
279 // 测试各种钩子函数不会崩溃
280 scheduler.OnScheduled(&task1);
281 scheduler.OnPreempted(&task1);
282 scheduler.BoostPriority(&task1, 10);
283 scheduler.RestorePriority(&task1);
284
285 // OnTick 应返回 false(FIFO 不需要基于 tick 的抢占)
286 bool need_resched = scheduler.OnTick(&task1);
287 EXPECT_EQ(need_resched, false, "OnTick should return false for FIFO");
288
289 // OnTimeSliceExpired 应返回 true(需要重新入队)
290 bool need_requeue = scheduler.OnTimeSliceExpired(&task1);
291 EXPECT_EQ(need_requeue, true,
292 "OnTimeSliceExpired should return true for FIFO");
293
294 // 验证调度器仍正常工作
295 scheduler.Enqueue(&task1);
296 auto* picked = scheduler.PickNext();
297 EXPECT_EQ(picked, &task1, "Scheduler should still work after hook calls");
298
299 klog::Info("test_fifo_hooks passed");
300 return true;
301}
302
303auto test_fifo_robustness() -> bool {
304 klog::Info("Running test_fifo_robustness...");
305
306 FifoScheduler scheduler;
307
308 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
309 task1.fsm.Receive(MsgSchedule{});
310
311 // 空队列操作
312 EXPECT_EQ(scheduler.PickNext(), nullptr,
313 "PickNext on empty queue should return nullptr");
314 scheduler.Dequeue(&task1); // 不应崩溃
315
316 // 重复移除
317 scheduler.Enqueue(&task1);
318 scheduler.Dequeue(&task1);
319 scheduler.Dequeue(&task1); // 再次移除已移除的任务,不应崩溃
320 EXPECT_TRUE(scheduler.IsEmpty(), "Scheduler should be empty");
321
322 klog::Info("test_fifo_robustness passed");
323 return true;
324}
325
326} // namespace
327
328auto fifo_scheduler_test() -> bool {
329 klog::Info("\n=== FIFO Scheduler System Tests ===\n");
330
331 if (!test_fifo_basic_functionality()) {
332 return false;
333 }
334
335 if (!test_fifo_ordering()) {
336 return false;
337 }
338
339 if (!test_fifo_dequeue()) {
340 return false;
341 }
342
343 if (!test_fifo_statistics()) {
344 return false;
345 }
346
347 if (!test_fifo_mixed_operations()) {
348 return false;
349 }
350
351 if (!test_fifo_repeated_enqueue()) {
352 return false;
353 }
354
355 if (!test_fifo_hooks()) {
356 return false;
357 }
358
359 if (!test_fifo_robustness()) {
360 return false;
361 }
362
363 klog::Info("=== All FIFO Scheduler Tests Passed ===\n");
364 return true;
365}
先来先服务 (FIFO) 调度器
auto Enqueue(TaskControlBlock *task) -> void override
将任务加入就绪队列尾部
auto OnPreempted(TaskControlBlock *task) -> void override
任务被抢占时调用
auto PickNext() -> TaskControlBlock *override
选择下一个要运行的任务(队列头部)
auto IsEmpty() const -> bool override
判断队列是否为空
auto GetQueueSize() const -> size_t override
获取就绪队列大小
auto Dequeue(TaskControlBlock *task) -> void override
从就绪队列中移除指定任务
virtual auto OnTick(TaskControlBlock *current) -> bool
Tick 更新:每个时钟中断时调用,用于更新调度器状态
virtual auto BoostPriority(TaskControlBlock *task, int new_priority) -> void
优先级提升:当任务持有资源时被更高优先级任务等待,提升其优先级
virtual auto RestorePriority(TaskControlBlock *task) -> void
优先级恢复:当任务释放资源后,恢复其原始优先级
virtual auto GetStats() const -> const Stats &
获取调度器统计信息
const char * name
调度器名称
virtual auto OnScheduled(TaskControlBlock *task) -> void
任务开始运行时调用 (从 Ready 变为 Running)
virtual auto ResetStats() -> void
重置统计信息
virtual auto OnTimeSliceExpired(TaskControlBlock *task) -> bool
时间片耗尽处理:当任务时间片用完时调用
auto Receive(const etl::imessage &msg) -> void
向 FSM 发送消息
Definition task_fsm.hpp:163
auto Info(etl::format_string< Args... > fmt, Args &&... args) -> void
以 INFO 级别记录日志
调度消息(无负载,用作事件)
任务控制块,管理进程/线程的核心数据结构
TaskFsm fsm
任务状态机
auto fifo_scheduler_test() -> bool
#define EXPECT_TRUE(cond, msg)
#define EXPECT_NE(val1, val2, msg)
#define EXPECT_EQ(val1, val2, msg)