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 <gtest/gtest.h>
8
9#include "kstd_vector"
11
12// 测试 FIFO 调度器的基本入队出队功能
13TEST(FifoSchedulerTest, BasicEnqueueDequeue) {
14 FifoScheduler scheduler;
15
16 // 验证调度器名称
17 EXPECT_STREQ(scheduler.name, "FIFO");
18
19 // 创建测试任务
20 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
21 task1.status = TaskStatus::kReady;
22
23 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
24 task2.status = TaskStatus::kReady;
25
26 // 测试空队列
27 EXPECT_TRUE(scheduler.IsEmpty());
28 EXPECT_EQ(scheduler.GetQueueSize(), 0);
29 EXPECT_EQ(scheduler.PickNext(), nullptr);
30
31 // 加入任务
32 scheduler.Enqueue(&task1);
33 EXPECT_FALSE(scheduler.IsEmpty());
34 EXPECT_EQ(scheduler.GetQueueSize(), 1);
35
36 scheduler.Enqueue(&task2);
37 EXPECT_EQ(scheduler.GetQueueSize(), 2);
38
39 // 测试 FIFO 顺序(先进先出)
40 EXPECT_EQ(scheduler.PickNext(), &task1);
41 EXPECT_EQ(scheduler.GetQueueSize(), 1);
42
43 EXPECT_EQ(scheduler.PickNext(), &task2);
44 EXPECT_EQ(scheduler.GetQueueSize(), 0);
45
46 EXPECT_EQ(scheduler.PickNext(), nullptr);
47 EXPECT_TRUE(scheduler.IsEmpty());
48}
49
50// 测试 FIFO 的顺序性
51TEST(FifoSchedulerTest, FifoOrdering) {
52 FifoScheduler scheduler;
53
54 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
55 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
56 TaskControlBlock task3("Task3", 3, nullptr, nullptr);
57 TaskControlBlock task4("Task4", 4, nullptr, nullptr);
58
59 // 按顺序加入任务
60 scheduler.Enqueue(&task1);
61 scheduler.Enqueue(&task2);
62 scheduler.Enqueue(&task3);
63 scheduler.Enqueue(&task4);
64
65 EXPECT_EQ(scheduler.GetQueueSize(), 4);
66
67 // 验证严格的 FIFO 顺序
68 EXPECT_EQ(scheduler.PickNext(), &task1);
69 EXPECT_EQ(scheduler.PickNext(), &task2);
70 EXPECT_EQ(scheduler.PickNext(), &task3);
71 EXPECT_EQ(scheduler.PickNext(), &task4);
72 EXPECT_EQ(scheduler.PickNext(), nullptr);
73}
74
75// 测试 Dequeue 功能(移除指定任务)
76TEST(FifoSchedulerTest, DequeueSpecificTask) {
77 FifoScheduler scheduler;
78
79 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
80 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
81 TaskControlBlock task3("Task3", 3, nullptr, nullptr);
82
83 scheduler.Enqueue(&task1);
84 scheduler.Enqueue(&task2);
85 scheduler.Enqueue(&task3);
86
87 EXPECT_EQ(scheduler.GetQueueSize(), 3);
88
89 // 移除中间的任务
90 scheduler.Dequeue(&task2);
91 EXPECT_EQ(scheduler.GetQueueSize(), 2);
92
93 // 验证只剩下 task1 和 task3
94 EXPECT_EQ(scheduler.PickNext(), &task1);
95 EXPECT_EQ(scheduler.PickNext(), &task3);
96 EXPECT_EQ(scheduler.PickNext(), nullptr);
97}
98
99// 测试移除队首任务
100TEST(FifoSchedulerTest, DequeueFirstTask) {
101 FifoScheduler scheduler;
102
103 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
104 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
105 TaskControlBlock task3("Task3", 3, nullptr, nullptr);
106
107 scheduler.Enqueue(&task1);
108 scheduler.Enqueue(&task2);
109 scheduler.Enqueue(&task3);
110
111 // 移除队首任务
112 scheduler.Dequeue(&task1);
113 EXPECT_EQ(scheduler.GetQueueSize(), 2);
114
115 // task2 现在应该是队首
116 EXPECT_EQ(scheduler.PickNext(), &task2);
117 EXPECT_EQ(scheduler.PickNext(), &task3);
118 EXPECT_EQ(scheduler.PickNext(), nullptr);
119}
120
121// 测试移除队尾任务
122TEST(FifoSchedulerTest, DequeueLastTask) {
123 FifoScheduler scheduler;
124
125 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
126 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
127 TaskControlBlock task3("Task3", 3, nullptr, nullptr);
128
129 scheduler.Enqueue(&task1);
130 scheduler.Enqueue(&task2);
131 scheduler.Enqueue(&task3);
132
133 // 移除队尾任务
134 scheduler.Dequeue(&task3);
135 EXPECT_EQ(scheduler.GetQueueSize(), 2);
136
137 EXPECT_EQ(scheduler.PickNext(), &task1);
138 EXPECT_EQ(scheduler.PickNext(), &task2);
139 EXPECT_EQ(scheduler.PickNext(), nullptr);
140}
141
142// 测试统计功能
143TEST(FifoSchedulerTest, Statistics) {
144 FifoScheduler scheduler;
145
146 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
147 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
148
149 // 初始状态
150 auto stats = scheduler.GetStats();
151 EXPECT_EQ(stats.total_enqueues, 0);
152 EXPECT_EQ(stats.total_dequeues, 0);
153 EXPECT_EQ(stats.total_picks, 0);
154 EXPECT_EQ(stats.total_preemptions, 0);
155
156 // 测试入队统计
157 scheduler.Enqueue(&task1);
158 scheduler.Enqueue(&task2);
159 stats = scheduler.GetStats();
160 EXPECT_EQ(stats.total_enqueues, 2);
161 EXPECT_EQ(stats.total_dequeues, 0);
162 EXPECT_EQ(stats.total_picks, 0);
163
164 // 测试选择统计
165 scheduler.PickNext();
166 stats = scheduler.GetStats();
167 EXPECT_EQ(stats.total_picks, 1);
168
169 // 测试出队统计
170 scheduler.Dequeue(&task2);
171 stats = scheduler.GetStats();
172 EXPECT_EQ(stats.total_dequeues, 1);
173
174 // 测试抢占统计
175 scheduler.OnPreempted(&task1);
176 stats = scheduler.GetStats();
177 EXPECT_EQ(stats.total_preemptions, 1);
178
179 // 测试重置统计
180 scheduler.ResetStats();
181 stats = scheduler.GetStats();
182 EXPECT_EQ(stats.total_enqueues, 0);
183 EXPECT_EQ(stats.total_dequeues, 0);
184 EXPECT_EQ(stats.total_picks, 0);
185 EXPECT_EQ(stats.total_preemptions, 0);
186}
187
188// 测试重复入队同一任务
189TEST(FifoSchedulerTest, RepeatedEnqueue) {
190 FifoScheduler scheduler;
191
192 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
193
194 // 多次入队同一任务(模拟时间片用完后重新入队)
195 scheduler.Enqueue(&task1);
196 scheduler.Enqueue(&task1);
197 scheduler.Enqueue(&task1);
198
199 EXPECT_EQ(scheduler.GetQueueSize(), 3);
200
201 // 应该能三次取出同一任务
202 EXPECT_EQ(scheduler.PickNext(), &task1);
203 EXPECT_EQ(scheduler.PickNext(), &task1);
204 EXPECT_EQ(scheduler.PickNext(), &task1);
205 EXPECT_EQ(scheduler.PickNext(), nullptr);
206}
207
208// 测试混合操作
209TEST(FifoSchedulerTest, MixedOperations) {
210 FifoScheduler scheduler;
211
212 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
213 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
214 TaskControlBlock task3("Task3", 3, nullptr, nullptr);
215 TaskControlBlock task4("Task4", 4, nullptr, nullptr);
216
217 // 加入 task1, task2, task3
218 scheduler.Enqueue(&task1);
219 scheduler.Enqueue(&task2);
220 scheduler.Enqueue(&task3);
221
222 // 取出 task1
223 EXPECT_EQ(scheduler.PickNext(), &task1);
224
225 // 加入 task4
226 scheduler.Enqueue(&task4);
227
228 // 移除 task3
229 scheduler.Dequeue(&task3);
230
231 // 现在队列应该是 [task2, task4]
232 EXPECT_EQ(scheduler.GetQueueSize(), 2);
233 EXPECT_EQ(scheduler.PickNext(), &task2);
234 EXPECT_EQ(scheduler.PickNext(), &task4);
235 EXPECT_EQ(scheduler.PickNext(), nullptr);
236}
237
238// 测试空队列操作的健壮性
239TEST(FifoSchedulerTest, EmptyQueueRobustness) {
240 FifoScheduler scheduler;
241
242 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
243
244 // 空队列操作
245 EXPECT_EQ(scheduler.PickNext(), nullptr);
246 EXPECT_EQ(scheduler.PickNext(), nullptr);
247 EXPECT_EQ(scheduler.GetQueueSize(), 0);
248 EXPECT_TRUE(scheduler.IsEmpty());
249
250 // 尝试移除不存在的任务(应该不崩溃)
251 scheduler.Dequeue(&task1);
252 EXPECT_EQ(scheduler.GetQueueSize(), 0);
253
254 // 加入后再测试
255 scheduler.Enqueue(&task1);
256 EXPECT_EQ(scheduler.GetQueueSize(), 1);
257
258 // 移除存在的任务
259 scheduler.Dequeue(&task1);
260 EXPECT_EQ(scheduler.GetQueueSize(), 0);
261 EXPECT_TRUE(scheduler.IsEmpty());
262}
263
264// 测试大量任务
265TEST(FifoSchedulerTest, LargeNumberOfTasks) {
266 FifoScheduler scheduler;
267 constexpr size_t kTaskCount = 100;
268
269 // 创建任务数组(使用动态分配)
270 kstd::vector<TaskControlBlock*> tasks;
271 for (size_t i = 0; i < kTaskCount; ++i) {
272 auto* task = new TaskControlBlock("Task", 10, nullptr, nullptr);
273 task->status = TaskStatus::kReady;
274 tasks.push_back(task);
275 scheduler.Enqueue(task);
276 }
277
278 EXPECT_EQ(scheduler.GetQueueSize(), kTaskCount);
279
280 // 验证 FIFO 顺序
281 for (size_t i = 0; i < kTaskCount; ++i) {
282 auto* picked = scheduler.PickNext();
283 EXPECT_NE(picked, nullptr);
284 EXPECT_EQ(picked, tasks[i]);
285 }
286
287 EXPECT_EQ(scheduler.PickNext(), nullptr);
288 EXPECT_TRUE(scheduler.IsEmpty());
289
290 // 清理内存
291 for (auto* task : tasks) {
292 delete task;
293 }
294}
295
296// 测试 OnTick 钩子(FIFO 不需要 tick 处理,应返回 false)
297TEST(FifoSchedulerTest, OnTickHook) {
298 FifoScheduler scheduler;
299
300 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
301
302 // FIFO 调度器的 OnTick 应该始终返回 false(不需要抢占)
303 EXPECT_FALSE(scheduler.OnTick(&task1));
304 EXPECT_FALSE(scheduler.OnTick(nullptr));
305}
306
307// 测试 OnTimeSliceExpired 钩子
308TEST(FifoSchedulerTest, OnTimeSliceExpiredHook) {
309 FifoScheduler scheduler;
310
311 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
312
313 // FIFO 调度器的 OnTimeSliceExpired 应返回 true(需要重新入队)
314 EXPECT_TRUE(scheduler.OnTimeSliceExpired(&task1));
315}
316
317// 测试优先级相关钩子(FIFO 不使用优先级,但接口应该可调用)
318TEST(FifoSchedulerTest, PriorityHooks) {
319 FifoScheduler scheduler;
320
321 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
322 task1.sched_info.priority = 5;
323
324 // 这些调用不应该崩溃(即使 FIFO 不使用优先级)
325 scheduler.BoostPriority(&task1, 10);
326 scheduler.RestorePriority(&task1);
327
328 // 验证调度器仍正常工作
329 scheduler.Enqueue(&task1);
330 EXPECT_EQ(scheduler.PickNext(), &task1);
331}
332
333// 测试调度器钩子的统计
334TEST(FifoSchedulerTest, SchedulerHooks) {
335 FifoScheduler scheduler;
336
337 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
338
339 // OnScheduled 和 OnPreempted 不影响队列
340 scheduler.Enqueue(&task1);
341 scheduler.OnScheduled(&task1);
342
343 EXPECT_EQ(scheduler.GetQueueSize(), 1);
344
345 auto* picked = scheduler.PickNext();
346 EXPECT_EQ(picked, &task1);
347
348 scheduler.OnPreempted(&task1);
349 auto stats = scheduler.GetStats();
350 EXPECT_EQ(stats.total_preemptions, 1);
351}
先来先服务 (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
时间片耗尽处理:当任务时间片用完时调用
constexpr etl::fsm_state_id_t kReady
Definition task_fsm.hpp:15
int priority
优先级 (数字越小优先级越高)
任务控制块,管理进程/线程的核心数据结构
struct TaskControlBlock::SchedInfo sched_info
#define EXPECT_TRUE(cond, msg)
#define EXPECT_NE(val1, val2, msg)
#define EXPECT_FALSE(cond, msg)
#define EXPECT_EQ(val1, val2, msg)
TEST(FifoSchedulerTest, BasicEnqueueDequeue)