14#include "kstd_cstring"
25std::atomic<int> g_wait_completed{0};
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);
36 klog::Info(
"Child {}: starting, will exit with code {}", child_id, exit_code);
39 for (
int i = 0; i < 5; ++i) {
40 klog::Debug(
"Child {}: working, iter={}", child_id, i);
44 klog::Info(
"Child {}: exiting with code {}", child_id, exit_code);
51void test_wait_basic(
void* ) {
54 auto& task_mgr = TaskManagerSingleton::instance();
55 auto* current = task_mgr.GetCurrentTask();
58 klog::Err(
"Wait Basic Test: Cannot get current task");
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;
69 task_mgr.AddTask(std::move(child));
71 klog::Info(
"Parent: created child with PID={}", child_pid);
75 Pid result = task_mgr.Wait(child_pid, &status,
false,
false).value_or(0);
77 if (result == child_pid) {
78 klog::Info(
"Parent: child {} exited with status {}", result, status);
83 "Wait Basic Test: FAIL - wrong exit status (got {}, expected "
88 klog::Err(
"Wait Basic Test: FAIL - wait returned {} (expected {})", result,
92 if (result == child_pid && status == 42) {
106void test_wait_any_child(
void* ) {
109 auto& task_mgr = TaskManagerSingleton::instance();
110 auto* current = task_mgr.GetCurrentTask();
113 klog::Err(
"Wait Any Child Test: Cannot get current task");
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);
131 for (
int i = 0; i < kChildCount; ++i) {
134 task_mgr.Wait(
static_cast<Pid>(-1), &status,
false,
false).value_or(0);
137 klog::Info(
"Parent: child PID={} exited with status {}", result, status);
140 klog::Err(
"Parent: wait failed with result {}", result);
145 if (completed == kChildCount) {
148 klog::Err(
"Wait Any Child Test: FAIL - only {}/{} children reaped",
149 completed, kChildCount);
159void slow_child_work(
void* arg) {
160 uint64_t child_id =
reinterpret_cast<uint64_t
>(arg);
162 klog::Info(
"SlowChild {}: starting", child_id);
165 for (
int i = 0; i < 10; ++i) {
166 klog::Debug(
"SlowChild {}: working, iter={}", child_id, i);
170 klog::Info(
"SlowChild {}: exiting", child_id);
174void test_wait_no_hang(
void* ) {
177 auto& task_mgr = TaskManagerSingleton::instance();
178 auto* current = task_mgr.GetCurrentTask();
181 klog::Err(
"Wait NoHang Test: Cannot get current task");
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));
193 klog::Info(
"Parent: created slow child with PID={}", child_pid);
197 Pid result = task_mgr.Wait(child_pid, &status,
true,
false).value_or(0);
200 klog::Info(
"Parent: no-hang wait returned 0 (child still running)");
204 "Wait NoHang Test: FAIL - expected 0, got {} (child shouldn't have "
210 result = task_mgr.Wait(child_pid, &status,
false,
false).value_or(0);
211 klog::Info(
"Parent: child finally exited with PID={}", result);
220void test_wait_process_group(
void* ) {
221 klog::Info(
"=== Wait Process Group Test ===");
223 auto& task_mgr = TaskManagerSingleton::instance();
224 auto* current = task_mgr.GetCurrentTask();
227 klog::Err(
"Wait Process Group Test: Cannot get current task");
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));
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));
248 klog::Info(
"Parent: created child1 (pgid={}) and child2 (pgid={})",
249 child1_pgid, child2_pgid);
253 Pid result = task_mgr.Wait(0, &status,
false,
false).value_or(0);
255 if (result == child1_pid) {
256 klog::Info(
"Parent: correctly waited for same-pgid child {}", result);
259 klog::Err(
"Wait Process Group Test: FAIL - got PID={}, expected {}", result,
264 result = task_mgr.Wait(child2_pid, &status,
false,
false).value_or(0);
265 klog::Info(
"Parent: cleaned up child2 PID={}", result);
274void zombie_child_work(
void* arg) {
275 uint64_t child_id =
reinterpret_cast<uint64_t
>(arg);
276 klog::Info(
"ZombieChild {}: exiting immediately", child_id);
281void test_wait_zombie_reap(
void* ) {
284 g_wait_completed = 0;
285 auto& task_mgr = TaskManagerSingleton::instance();
286 auto* current = task_mgr.GetCurrentTask();
289 klog::Err(
"Wait Zombie Reap Test: Cannot get current task");
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));
301 klog::Info(
"Parent: created zombie child with PID={}", child_pid);
308 Pid result = task_mgr.Wait(child_pid, &status,
false,
false).value_or(0);
310 if (result == child_pid) {
311 klog::Info(
"Parent: successfully reaped zombie child {}", result);
314 klog::Err(
"Wait Zombie Reap Test: FAIL - wait returned {}", result);
329 g_tests_completed = 0;
332 auto& task_mgr = TaskManagerSingleton::instance();
335 auto test1 = kstd::make_unique<TaskControlBlock>(
"TestWaitBasic", 10,
336 test_wait_basic,
nullptr);
337 task_mgr.AddTask(std::move(test1));
340 auto test2 = kstd::make_unique<TaskControlBlock>(
341 "TestWaitAnyChild", 10, test_wait_any_child,
nullptr);
342 task_mgr.AddTask(std::move(test2));
345 auto test3 = kstd::make_unique<TaskControlBlock>(
"TestWaitNoHang", 10,
346 test_wait_no_hang,
nullptr);
347 task_mgr.AddTask(std::move(test3));
350 auto test4 = kstd::make_unique<TaskControlBlock>(
351 "TestWaitProcessGroup", 10, test_wait_process_group,
nullptr);
352 task_mgr.AddTask(std::move(test4));
355 auto test5 = kstd::make_unique<TaskControlBlock>(
356 "TestWaitZombieReap", 10, test_wait_zombie_reap,
nullptr);
357 task_mgr.AddTask(std::move(test5));
360 constexpr int kExpectedTests = 5;
362 while (timeout > 0) {
364 if (g_tests_completed >= kExpectedTests) {
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");
374 klog::Info(
"Wait System Test Suite: COMPLETED");
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
休眠指定毫秒数
auto sys_exit(int code) -> int
退出当前进程或线程
#define EXPECT_EQ(val1, val2, msg)
auto wait_system_test() -> bool
Wait 系统测试入口