15#include "kstd_cstring"
27std::atomic<int> g_exit_test_counter{0};
28std::atomic<int> g_tests_completed{0};
29std::atomic<int> g_tests_failed{0};
37void normal_work(
void* arg) {
38 auto* flag =
reinterpret_cast<std::atomic<int>*
>(arg);
42 klog::Debug(
"normal_work: done, calling sys_exit(0)");
46void test_exit_normal(
void* ) {
54 task->aux->tgid = 5000;
55 task->aux->parent_pid = 1;
59 klog::Err(
"test_exit_normal: FAIL — fresh TCB already in terminal state");
64 if (task->aux->exit_code != 0) {
65 klog::Err(
"test_exit_normal: FAIL — default exit_code != 0 (got {})",
66 task->aux->exit_code);
71 std::atomic<int> work_flag{0};
72 auto worker = kstd::make_unique<TaskControlBlock>(
73 "ExitNormalWorker", 10, normal_work,
reinterpret_cast<void*
>(&work_flag));
74 TaskManagerSingleton::instance().AddTask(std::move(worker));
78 while (timeout > 0 && work_flag.load() == 0) {
83 if (work_flag.load() != 1) {
84 klog::Err(
"test_exit_normal: FAIL — worker did not complete");
87 klog::Info(
"test_exit_normal: worker completed successfully");
91 task->aux->exit_code = 0;
94 task->fsm.Receive(
MsgExit{0,
true});
96 klog::Err(
"test_exit_normal: FAIL — TCB field write-back mismatch");
117void error_work(
void* arg) {
118 auto* flag =
reinterpret_cast<std::atomic<int>*
>(arg);
122 klog::Debug(
"error_work: done, calling sys_exit(42)");
126void test_exit_with_error(
void* ) {
134 task->aux->tgid = 5001;
135 task->aux->parent_pid = 1;
137 if (task->aux->exit_code != 0) {
138 klog::Err(
"test_exit_with_error: FAIL — default exit_code != 0 (got {})",
139 task->aux->exit_code);
144 std::atomic<int> work_flag{0};
145 auto worker = kstd::make_unique<TaskControlBlock>(
146 "ExitErrorWorker", 10, error_work,
reinterpret_cast<void*
>(&work_flag));
147 TaskManagerSingleton::instance().AddTask(std::move(worker));
150 while (timeout > 0 && work_flag.load() == 0) {
155 if (work_flag.load() != 42) {
156 klog::Err(
"test_exit_with_error: FAIL — worker did not set error flag");
159 klog::Info(
"test_exit_with_error: worker set flag to {}", work_flag.load());
163 task->aux->exit_code = 42;
166 task->fsm.Receive(
MsgExit{42,
true});
167 if (task->aux->exit_code != 42) {
169 "test_exit_with_error: FAIL — exit_code write-back mismatch "
170 "(expected 42, got {})",
171 task->aux->exit_code);
175 klog::Err(
"test_exit_with_error: FAIL — status write-back mismatch");
182 klog::Err(
"Exit With Error Test: FAILED");
195void child_thread_exit_work(
void* arg) {
196 uint64_t thread_id =
reinterpret_cast<uint64_t
>(arg);
200 for (
int i = 0; i < 3; ++i) {
201 g_exit_test_counter++;
202 klog::Debug(
"Thread {}: working, iter={}", thread_id, i);
207 sys_exit(
static_cast<int>(thread_id));
210void test_thread_exit(
void* ) {
213 g_exit_test_counter = 0;
217 kstd::make_unique<TaskControlBlock>(
"ThreadLeader", 10,
nullptr,
nullptr);
218 leader_uptr->pid = 5100;
219 leader_uptr->aux->tgid = 5100;
220 leader_uptr->aux->parent_pid = 1;
221 auto* leader = leader_uptr.get();
223 TaskManagerSingleton::instance().AddTask(std::move(leader_uptr));
226 auto thread1 = kstd::make_unique<TaskControlBlock>(
227 "Thread1", 10, child_thread_exit_work,
reinterpret_cast<void*
>(1));
229 thread1->aux->tgid = 5100;
230 thread1->JoinThreadGroup(leader);
232 TaskManagerSingleton::instance().AddTask(std::move(thread1));
234 auto thread2 = kstd::make_unique<TaskControlBlock>(
235 "Thread2", 10, child_thread_exit_work,
reinterpret_cast<void*
>(2));
237 thread2->aux->tgid = 5100;
238 thread2->JoinThreadGroup(leader);
240 TaskManagerSingleton::instance().AddTask(std::move(thread2));
242 klog::Info(
"Created thread group with leader (pid={}) and 2 threads",
248 klog::Info(
"Exit test counter: {} (expected >= 6)",
249 g_exit_test_counter.load());
251 bool passed = (g_exit_test_counter.load() >= 6);
256 klog::Err(
"Thread Exit Test: FAILED (counter={}, expected >= 6)",
257 g_exit_test_counter.load());
272void orphan_work(
void* arg) {
273 auto* flag =
reinterpret_cast<std::atomic<int>*
>(arg);
281void test_orphan_exit(
void* ) {
289 orphan->aux->tgid = 5200;
290 orphan->aux->parent_pid = 0;
292 if (orphan->aux->parent_pid != 0) {
293 klog::Err(
"test_orphan_exit: FAIL — parent_pid not stored as 0 (got {})",
294 orphan->aux->parent_pid);
299 orphan->aux->exit_code = 0;
302 orphan->fsm.Receive(
MsgExit{0,
false});
305 "test_orphan_exit: FAIL — orphan status should be kExited "
307 static_cast<int>(orphan->GetStatus()));
310 if (orphan->aux->parent_pid != 0) {
311 klog::Err(
"test_orphan_exit: FAIL — parent_pid changed unexpectedly");
316 std::atomic<int> work_flag{0};
317 auto orphan_worker = kstd::make_unique<TaskControlBlock>(
318 "OrphanWorker", 10, orphan_work,
reinterpret_cast<void*
>(&work_flag));
319 orphan_worker->aux->parent_pid = 0;
320 TaskManagerSingleton::instance().AddTask(std::move(orphan_worker));
323 while (timeout > 0 && work_flag.load() == 0) {
328 if (work_flag.load() != 1) {
329 klog::Err(
"test_orphan_exit: FAIL — orphan worker did not complete");
332 klog::Info(
"test_orphan_exit: orphan worker completed");
354void child_work(
void* arg) {
355 auto* flag =
reinterpret_cast<std::atomic<int>*
>(arg);
363void test_zombie_process(
void* ) {
370 kstd::make_unique<TaskControlBlock>(
"Parent", 10,
nullptr,
nullptr);
371 parent_uptr->pid = 5300;
372 parent_uptr->aux->tgid = 5300;
373 parent_uptr->aux->parent_pid = 1;
374 auto* parent = parent_uptr.get();
376 TaskManagerSingleton::instance().AddTask(std::move(parent_uptr));
380 local_child->pid = 5301;
381 local_child->aux->tgid = 5301;
382 local_child->aux->parent_pid = parent->pid;
384 if (local_child->aux->parent_pid != parent->pid) {
386 "test_zombie_process: FAIL — child parent_pid mismatch "
387 "(expected {}, got {})",
388 parent->pid, local_child->aux->parent_pid);
392 local_child->aux->exit_code = 0;
395 local_child->fsm.Receive(
399 "test_zombie_process: FAIL — child with living parent should be "
401 static_cast<int>(local_child->GetStatus()));
404 if (local_child->aux->parent_pid != parent->pid) {
406 "test_zombie_process: FAIL — child parent_pid changed after "
411 klog::Info(
"Child process (pid={}) became zombie, waiting for parent to reap",
417 std::atomic<int> work_flag{0};
418 auto real_child = kstd::make_unique<TaskControlBlock>(
419 "RealChild", 10, child_work,
reinterpret_cast<void*
>(&work_flag));
420 real_child->aux->parent_pid = 5300;
421 TaskManagerSingleton::instance().AddTask(std::move(real_child));
424 while (timeout > 0 && work_flag.load() == 0) {
429 if (work_flag.load() != 1) {
430 klog::Err(
"test_zombie_process: FAIL — child worker did not complete");
433 klog::Info(
"test_zombie_process: child worker completed");
439 klog::Err(
"Zombie Process Test: FAILED");
453 klog::Info(
"===== Exit System Test Start =====");
456 g_tests_completed = 0;
458 g_exit_test_counter = 0;
460 auto& task_mgr = TaskManagerSingleton::instance();
463 auto test1 = kstd::make_unique<TaskControlBlock>(
"TestExitNormal", 10,
464 test_exit_normal,
nullptr);
465 task_mgr.AddTask(std::move(test1));
468 auto test2 = kstd::make_unique<TaskControlBlock>(
469 "TestExitWithError", 10, test_exit_with_error,
nullptr);
470 task_mgr.AddTask(std::move(test2));
473 auto test3 = kstd::make_unique<TaskControlBlock>(
"TestThreadExit", 10,
474 test_thread_exit,
nullptr);
475 task_mgr.AddTask(std::move(test3));
478 auto test4 = kstd::make_unique<TaskControlBlock>(
"TestOrphanExit", 10,
479 test_orphan_exit,
nullptr);
480 task_mgr.AddTask(std::move(test4));
483 auto test5 = kstd::make_unique<TaskControlBlock>(
484 "TestZombieProcess", 10, test_zombie_process,
nullptr);
485 task_mgr.AddTask(std::move(test5));
487 klog::Info(
"Waiting for all 5 sub-tests to complete...");
492 while (timeout > 0) {
494 if (g_tests_completed.load() >= 5) {
500 klog::Info(
"Exit System Test: completed={}, failed={}",
501 g_tests_completed.load(), g_tests_failed.load());
503 EXPECT_EQ(g_tests_completed, 5,
"All 5 sub-tests completed");
504 EXPECT_EQ(g_tests_failed, 0,
"No sub-tests failed");
506 klog::Info(
"===== Exit System Test End =====");
auto exit_system_test() -> bool
Exit 系统测试入口
constexpr etl::fsm_state_id_t kExited
constexpr etl::fsm_state_id_t kZombie
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)