SimpleKernel 1.17.0
Loading...
Searching...
No Matches
wait_system_test.cpp
Go to the documentation of this file.
1
5#include <cpu_io.h>
6
7#include <atomic>
8#include <cstddef>
9#include <cstdint>
10
11#include "arch.h"
12#include "basic_info.hpp"
13#include "kernel.h"
14#include "kstd_cstring"
15#include "kstd_libcxx.h"
16#include "kstd_memory"
17#include "sk_stdlib.h"
18#include "syscall.hpp"
19#include "system_test.h"
21#include "task_manager.hpp"
22
23namespace {
24
25std::atomic<int> g_wait_completed{0};
26
27std::atomic<int> g_tests_completed{0};
28std::atomic<int> g_tests_failed{0};
32void child_work(void* arg) {
33 uint64_t child_id = reinterpret_cast<uint64_t>(arg);
34 int exit_code = static_cast<int>(child_id);
35
36 klog::Info("Child {}: starting, will exit with code {}", child_id, exit_code);
37
38 // 执行一些工作
39 for (int i = 0; i < 5; ++i) {
40 klog::Debug("Child {}: working, iter={}", child_id, i);
41 (void)sys_sleep(30);
42 }
43
44 klog::Info("Child {}: exiting with code {}", child_id, exit_code);
45 sys_exit(exit_code);
46}
47
51void test_wait_basic(void* /*arg*/) {
52 klog::Info("=== Wait Basic Test ===");
53
54 auto& task_mgr = TaskManagerSingleton::instance();
55 auto* current = task_mgr.GetCurrentTask();
56
57 if (!current) {
58 klog::Err("Wait Basic Test: Cannot get current task");
59 sys_exit(1);
60 }
61
62 // 创建子进程
63 auto child = kstd::make_unique<TaskControlBlock>("WaitChild", 10, child_work,
64 reinterpret_cast<void*>(42));
65 child->aux->parent_pid = current->pid;
66 child->aux->pgid = current->aux->pgid;
67 Pid child_pid = child->pid;
68
69 task_mgr.AddTask(std::move(child));
70
71 klog::Info("Parent: created child with PID={}", child_pid);
72
73 // 等待子进程退出
74 int status = 0;
75 Pid result = task_mgr.Wait(child_pid, &status, false, false).value_or(0);
76
77 if (result == child_pid) {
78 klog::Info("Parent: child {} exited with status {}", result, status);
79 if (status == 42) {
80 klog::Info("Wait Basic Test: PASS");
81 } else {
83 "Wait Basic Test: FAIL - wrong exit status (got {}, expected "
84 "42)",
85 status);
86 }
87 } else {
88 klog::Err("Wait Basic Test: FAIL - wait returned {} (expected {})", result,
89 child_pid);
90 }
91
92 if (result == child_pid && status == 42) {
93 klog::Info("Wait Basic Test: PASS");
94 } else {
95 klog::Err("Wait Basic Test: FAIL");
96 g_tests_failed++;
97 }
98
99 g_tests_completed++;
100 sys_exit(0);
101}
102
106void test_wait_any_child(void* /*arg*/) {
107 klog::Info("=== Wait Any Child Test ===");
108
109 auto& task_mgr = TaskManagerSingleton::instance();
110 auto* current = task_mgr.GetCurrentTask();
111
112 if (!current) {
113 klog::Err("Wait Any Child Test: Cannot get current task");
114 sys_exit(1);
115 }
116
117 // 创建多个子进程
118 constexpr int kChildCount = 3;
119 for (int i = 0; i < kChildCount; ++i) {
120 auto child = kstd::make_unique<TaskControlBlock>(
121 "AnyChild", 10, child_work, reinterpret_cast<void*>(10 + i));
122 child->aux->parent_pid = current->pid;
123 child->aux->pgid = current->aux->pgid;
124 Pid child_pid = child->pid;
125 task_mgr.AddTask(std::move(child));
126 klog::Info("Parent: created child {} with PID={}", i, child_pid);
127 }
128
129 // 等待任意子进程 (pid = -1)
130 int completed = 0;
131 for (int i = 0; i < kChildCount; ++i) {
132 int status = 0;
133 Pid result =
134 task_mgr.Wait(static_cast<Pid>(-1), &status, false, false).value_or(0);
135
136 if (result > 0) {
137 klog::Info("Parent: child PID={} exited with status {}", result, status);
138 completed++;
139 } else {
140 klog::Err("Parent: wait failed with result {}", result);
141 break;
142 }
143 }
144
145 if (completed == kChildCount) {
146 klog::Info("Wait Any Child Test: PASS");
147 } else {
148 klog::Err("Wait Any Child Test: FAIL - only {}/{} children reaped",
149 completed, kChildCount);
150 }
151
152 g_tests_completed++;
153 sys_exit(0);
154}
155
159void slow_child_work(void* arg) {
160 uint64_t child_id = reinterpret_cast<uint64_t>(arg);
161
162 klog::Info("SlowChild {}: starting", child_id);
163
164 // 执行较长时间的工作
165 for (int i = 0; i < 10; ++i) {
166 klog::Debug("SlowChild {}: working, iter={}", child_id, i);
167 (void)sys_sleep(100);
168 }
169
170 klog::Info("SlowChild {}: exiting", child_id);
171 sys_exit(0);
172}
173
174void test_wait_no_hang(void* /*arg*/) {
175 klog::Info("=== Wait NoHang Test ===");
176
177 auto& task_mgr = TaskManagerSingleton::instance();
178 auto* current = task_mgr.GetCurrentTask();
179
180 if (!current) {
181 klog::Err("Wait NoHang Test: Cannot get current task");
182 sys_exit(1);
183 }
184
185 // 创建一个慢速子进程
186 auto child = kstd::make_unique<TaskControlBlock>(
187 "SlowChild", 10, slow_child_work, reinterpret_cast<void*>(1));
188 child->aux->parent_pid = current->pid;
189 child->aux->pgid = current->aux->pgid;
190 Pid child_pid = child->pid;
191 task_mgr.AddTask(std::move(child));
192
193 klog::Info("Parent: created slow child with PID={}", child_pid);
194
195 // 立即尝试非阻塞 wait
196 int status = 0;
197 Pid result = task_mgr.Wait(child_pid, &status, true, false).value_or(0);
198
199 if (result == 0) {
200 klog::Info("Parent: no-hang wait returned 0 (child still running)");
201 klog::Info("Wait NoHang Test: PASS");
202 } else {
203 klog::Err(
204 "Wait NoHang Test: FAIL - expected 0, got {} (child shouldn't have "
205 "exited)",
206 result);
207 }
208
209 // 清理:等待子进程实际退出(阻塞)
210 result = task_mgr.Wait(child_pid, &status, false, false).value_or(0);
211 klog::Info("Parent: child finally exited with PID={}", result);
212
213 g_tests_completed++;
214 sys_exit(0);
215}
216
220void test_wait_process_group(void* /*arg*/) {
221 klog::Info("=== Wait Process Group Test ===");
222
223 auto& task_mgr = TaskManagerSingleton::instance();
224 auto* current = task_mgr.GetCurrentTask();
225
226 if (!current) {
227 klog::Err("Wait Process Group Test: Cannot get current task");
228 sys_exit(1);
229 }
230
231 // 创建同进程组的子进程
232 auto child1 = kstd::make_unique<TaskControlBlock>("PgChild1", 10, child_work,
233 reinterpret_cast<void*>(1));
234 child1->aux->parent_pid = current->pid;
235 child1->aux->pgid = current->aux->pgid; // 同一进程组
236 Pid child1_pid = child1->pid;
237 Pid child1_pgid = child1->aux->pgid;
238 task_mgr.AddTask(std::move(child1));
239
240 auto child2 = kstd::make_unique<TaskControlBlock>("PgChild2", 10, child_work,
241 reinterpret_cast<void*>(2));
242 child2->aux->parent_pid = current->pid;
243 child2->aux->pgid = 9999; // 不同进程组
244 Pid child2_pid = child2->pid;
245 Pid child2_pgid = child2->aux->pgid;
246 task_mgr.AddTask(std::move(child2));
247
248 klog::Info("Parent: created child1 (pgid={}) and child2 (pgid={})",
249 child1_pgid, child2_pgid);
250
251 // 等待同进程组的子进程 (pid = 0)
252 int status = 0;
253 Pid result = task_mgr.Wait(0, &status, false, false).value_or(0);
254
255 if (result == child1_pid) {
256 klog::Info("Parent: correctly waited for same-pgid child {}", result);
257 klog::Info("Wait Process Group Test: PASS");
258 } else {
259 klog::Err("Wait Process Group Test: FAIL - got PID={}, expected {}", result,
260 child1_pid);
261 }
262
263 // 清理另一个子进程
264 result = task_mgr.Wait(child2_pid, &status, false, false).value_or(0);
265 klog::Info("Parent: cleaned up child2 PID={}", result);
266
267 g_tests_completed++;
268 sys_exit(0);
269}
270
274void zombie_child_work(void* arg) {
275 uint64_t child_id = reinterpret_cast<uint64_t>(arg);
276 klog::Info("ZombieChild {}: exiting immediately", child_id);
277 g_wait_completed++;
278 sys_exit(0);
279}
280
281void test_wait_zombie_reap(void* /*arg*/) {
282 klog::Info("=== Wait Zombie Reap Test ===");
283
284 g_wait_completed = 0;
285 auto& task_mgr = TaskManagerSingleton::instance();
286 auto* current = task_mgr.GetCurrentTask();
287
288 if (!current) {
289 klog::Err("Wait Zombie Reap Test: Cannot get current task");
290 sys_exit(1);
291 }
292
293 // 创建快速退出的子进程(会变成僵尸)
294 auto child = kstd::make_unique<TaskControlBlock>(
295 "ZombieChild", 10, zombie_child_work, reinterpret_cast<void*>(1));
296 child->aux->parent_pid = current->pid;
297 child->aux->pgid = current->aux->pgid;
298 Pid child_pid = child->pid;
299 task_mgr.AddTask(std::move(child));
300
301 klog::Info("Parent: created zombie child with PID={}", child_pid);
302
303 // 等待一段时间让子进程变成僵尸
304 (void)sys_sleep(200);
305
306 // 回收僵尸进程
307 int status = 0;
308 Pid result = task_mgr.Wait(child_pid, &status, false, false).value_or(0);
309
310 if (result == child_pid) {
311 klog::Info("Parent: successfully reaped zombie child {}", result);
312 klog::Info("Wait Zombie Reap Test: PASS");
313 } else {
314 klog::Err("Wait Zombie Reap Test: FAIL - wait returned {}", result);
315 }
316
317 g_tests_completed++;
318 sys_exit(0);
319}
320
321} // namespace
322
326auto wait_system_test() -> bool {
327 klog::Info("=== Wait System Test Suite ===");
328
329 g_tests_completed = 0;
330 g_tests_failed = 0;
331
332 auto& task_mgr = TaskManagerSingleton::instance();
333
334 // 测试 1: 基本 wait 功能
335 auto test1 = kstd::make_unique<TaskControlBlock>("TestWaitBasic", 10,
336 test_wait_basic, nullptr);
337 task_mgr.AddTask(std::move(test1));
338
339 // 测试 2: 等待任意子进程
340 auto test2 = kstd::make_unique<TaskControlBlock>(
341 "TestWaitAnyChild", 10, test_wait_any_child, nullptr);
342 task_mgr.AddTask(std::move(test2));
343
344 // 测试 3: 非阻塞 wait
345 auto test3 = kstd::make_unique<TaskControlBlock>("TestWaitNoHang", 10,
346 test_wait_no_hang, nullptr);
347 task_mgr.AddTask(std::move(test3));
348
349 // 测试 4: 进程组 wait
350 auto test4 = kstd::make_unique<TaskControlBlock>(
351 "TestWaitProcessGroup", 10, test_wait_process_group, nullptr);
352 task_mgr.AddTask(std::move(test4));
353
354 // 测试 5: 僵尸进程回收
355 auto test5 = kstd::make_unique<TaskControlBlock>(
356 "TestWaitZombieReap", 10, test_wait_zombie_reap, nullptr);
357 task_mgr.AddTask(std::move(test5));
358
359 // 同步等待所有测试完成
360 constexpr int kExpectedTests = 5;
361 int timeout = 400;
362 while (timeout > 0) {
363 (void)sys_sleep(50);
364 if (g_tests_completed >= kExpectedTests) {
365 break;
366 }
367 timeout--;
368 }
369
370 EXPECT_EQ(g_tests_completed.load(), kExpectedTests,
371 "All wait tests should complete");
372 EXPECT_EQ(g_tests_failed.load(), 0, "No wait tests should fail");
373
374 klog::Info("Wait System Test Suite: COMPLETED");
375 return true;
376}
auto Err(etl::format_string< Args... > fmt, Args &&... args) -> void
以 ERROR 级别记录日志
auto Info(etl::format_string< Args... > fmt, Args &&... args) -> void
以 INFO 级别记录日志
auto Debug(etl::format_string< Args... > fmt, Args &&... args) -> void
以 DEBUG 级别记录日志(SIMPLEKERNEL_MIN_LOG_LEVEL > 0 时编译期消除)
auto sys_sleep(uint64_t ms) -> int
休眠指定毫秒数
Definition syscall.cpp:90
auto sys_exit(int code) -> int
退出当前进程或线程
Definition syscall.cpp:75
#define EXPECT_EQ(val1, val2, msg)
size_t Pid
进程 ID 类型
auto wait_system_test() -> bool
Wait 系统测试入口