15#include "kstd_cstring"
26std::atomic<int> g_tests_completed{0};
27std::atomic<int> g_tests_failed{0};
29std::atomic<Pid> g_child1_pid{0};
30std::atomic<Pid> g_child1_tgid{0};
31std::atomic<Pid> g_child1_parent_pid{0};
32std::atomic<Pid> g_child2_pid{0};
33std::atomic<Pid> g_child2_tgid{0};
34std::atomic<Pid> g_child2_parent_pid{0};
35std::atomic<int> g_process_done{0};
37std::atomic<Pid> g_leader_pid{0};
38std::atomic<Pid> g_thread1_pid{0};
39std::atomic<Pid> g_thread1_tgid{0};
40std::atomic<Pid> g_thread2_pid{0};
41std::atomic<Pid> g_thread2_tgid{0};
42std::atomic<int> g_thread_done{0};
43std::atomic<bool> g_threads_may_exit{
false};
45std::atomic<uint64_t> g_flags_value{0};
46std::atomic<int> g_flags_done{0};
48void child_process_work(
void* arg) {
49 auto* current = TaskManagerSingleton::instance().GetCurrentTask();
50 uint64_t child_id =
reinterpret_cast<uint64_t
>(arg);
52 g_child1_pid.store(current->pid);
53 g_child1_tgid.store(current->aux->tgid);
54 g_child1_parent_pid.store(current->aux->parent_pid);
56 g_child2_pid.store(current->pid);
57 g_child2_tgid.store(current->aux->tgid);
58 g_child2_parent_pid.store(current->aux->parent_pid);
64void child_thread_work(
void* arg) {
65 auto* current = TaskManagerSingleton::instance().GetCurrentTask();
66 uint64_t thread_id =
reinterpret_cast<uint64_t
>(arg);
68 g_thread1_pid.store(current->pid);
69 g_thread1_tgid.store(current->aux->tgid);
71 g_thread2_pid.store(current->pid);
72 g_thread2_tgid.store(current->aux->tgid);
75 while (!g_threads_may_exit.load()) {
81void leader_work(
void* ) {
82 auto* current = TaskManagerSingleton::instance().GetCurrentTask();
83 g_leader_pid.store(current->pid);
88void flags_reporter_work(
void* ) {
89 auto* current = TaskManagerSingleton::instance().GetCurrentTask();
90 g_flags_value.store(current->aux->clone_flags.value());
95void noop_work(
void* ) {
sys_exit(0); }
97void test_clone_process(
void* ) {
104 g_child1_parent_pid = 0;
107 g_child2_parent_pid = 0;
109 auto* self = TaskManagerSingleton::instance().GetCurrentTask();
110 Pid my_pid = self->pid;
112 auto child1 = kstd::make_unique<TaskControlBlock>(
113 "CloneChild1", 10, child_process_work,
reinterpret_cast<void*
>(1));
114 child1->aux->parent_pid = my_pid;
115 TaskManagerSingleton::instance().AddTask(std::move(child1));
117 auto child2 = kstd::make_unique<TaskControlBlock>(
118 "CloneChild2", 10, child_process_work,
reinterpret_cast<void*
>(2));
119 child2->aux->parent_pid = my_pid;
120 TaskManagerSingleton::instance().AddTask(std::move(child2));
124 Pid c1_pid = g_child1_pid.load();
125 Pid c1_tgid = g_child1_tgid.load();
126 Pid c2_pid = g_child2_pid.load();
127 Pid c2_tgid = g_child2_tgid.load();
129 if (c1_pid == 0 || c2_pid == 0) {
130 klog::Err(
"Child processes did not start");
134 if (passed && (c1_tgid != c1_pid || c2_tgid != c2_pid)) {
135 klog::Err(
"Child tgid != pid: c1 tgid={} pid={}, c2 tgid={} pid={}",
136 c1_tgid, c1_pid, c2_tgid, c2_pid);
140 if (passed && (g_child1_parent_pid.load() != my_pid ||
141 g_child2_parent_pid.load() != my_pid)) {
142 klog::Err(
"Parent-child relationship incorrect");
146 if (passed && g_process_done.load() < 2) {
147 klog::Err(
"Not all child processes completed");
162void test_clone_thread(
void* ) {
167 g_threads_may_exit =
false;
174 auto leader_ptr = kstd::make_unique<TaskControlBlock>(
"CloneThreadLeader", 10,
175 leader_work,
nullptr);
176 TaskManagerSingleton::instance().AddTask(std::move(leader_ptr));
178 for (
int i = 0; i < 100 && g_leader_pid.load() == 0; ++i) {
182 Pid leader_pid = g_leader_pid.load();
183 if (leader_pid == 0) {
190 auto* leader = TaskManagerSingleton::instance().FindTask(leader_pid);
192 klog::Err(
"Leader not found in task table");
201 auto thread1 = kstd::make_unique<TaskControlBlock>(
202 "CloneThread1", 10, child_thread_work,
reinterpret_cast<void*
>(1));
203 thread1->aux->parent_pid = leader_pid;
204 thread1->aux->tgid = leader_pid;
205 thread1->aux->clone_flags =
static_cast<CloneFlags>(flags);
206 thread1->JoinThreadGroup(leader);
207 TaskManagerSingleton::instance().AddTask(std::move(thread1));
209 auto thread2 = kstd::make_unique<TaskControlBlock>(
210 "CloneThread2", 10, child_thread_work,
reinterpret_cast<void*
>(2));
211 thread2->aux->parent_pid = leader_pid;
212 thread2->aux->tgid = leader_pid;
213 thread2->aux->clone_flags =
static_cast<CloneFlags>(flags);
214 thread2->JoinThreadGroup(leader);
215 TaskManagerSingleton::instance().AddTask(std::move(thread2));
217 for (
int i = 0; i < 100 && g_thread_done.load() < 2; ++i) {
221 Pid t1_tgid = g_thread1_tgid.load();
222 Pid t2_tgid = g_thread2_tgid.load();
224 if (t1_tgid != leader_pid || t2_tgid != leader_pid) {
225 klog::Err(
"Thread tgid mismatch: t1={} t2={} expected={}", t1_tgid, t2_tgid,
230 if (g_thread1_pid.load() == g_thread2_pid.load()) {
231 klog::Err(
"Threads have identical PIDs");
235 size_t group_size = leader->GetThreadGroupSize();
236 if (group_size != 3) {
237 klog::Err(
"Thread group size is {}, expected 3", group_size);
241 g_threads_may_exit =
true;
254void test_clone_parent_flag(
void* ) {
260 auto task = kstd::make_unique<TaskControlBlock>(
"DefaultTask", 10,
262 if (task->aux->parent_pid != 0) {
263 klog::Err(
"Default parent_pid is not 0");
266 if (task->aux->tgid != 0) {
270 if (task->aux->clone_flags.value() != 0) {
271 klog::Err(
"Default clone_flags is not empty");
275 auto* raw = task.get();
276 TaskManagerSingleton::instance().AddTask(std::move(task));
282 if (raw->aux->tgid != raw->pid) {
283 klog::Err(
"AddTask did not set tgid=pid: tgid={} pid={}", raw->aux->tgid,
290 auto leader = kstd::make_unique<TaskControlBlock>(
"JoinLeader", 10,
292 auto* leader_raw = leader.get();
293 TaskManagerSingleton::instance().AddTask(std::move(leader));
295 auto member = kstd::make_unique<TaskControlBlock>(
"JoinMember", 10,
297 member->JoinThreadGroup(leader_raw);
298 auto* member_raw = member.get();
299 TaskManagerSingleton::instance().AddTask(std::move(member));
301 if (member_raw->aux->tgid != leader_raw->aux->tgid) {
302 klog::Err(
"JoinThreadGroup did not link tgid: member={} leader={}",
303 member_raw->aux->tgid, leader_raw->aux->tgid);
309 auto task = kstd::make_unique<TaskControlBlock>(
"FieldTest", 10, noop_work,
311 task->aux->parent_pid = 42;
312 task->aux->pgid = 99;
314 task->aux->clone_flags =
317 if (task->aux->parent_pid != 42) {
318 klog::Err(
"clone_flags assignment corrupted parent_pid");
321 if (task->aux->pgid != 99) {
322 klog::Err(
"clone_flags assignment corrupted pgid");
325 if (task->aux->sid != 7) {
326 klog::Err(
"clone_flags assignment corrupted sid");
338 TaskManagerSingleton::instance().AddTask(std::move(task));
344 klog::Err(
"Clone Parent Flag Test: FAILED");
352void test_clone_flags_auto_completion(
void* ) {
353 klog::Info(
"=== Clone Flags Auto Completion Test ===");
361 if (empty_flags.value() != 0) {
362 klog::Err(
"Default CloneFlags is not 0");
369 klog::Err(
"kThread not set in combined flags");
373 klog::Err(
"kVm not set in combined flags");
377 klog::Err(
"kFiles not set in combined flags");
391 uint64_t expected_flags =
393 auto task = kstd::make_unique<TaskControlBlock>(
394 "FlagsTask", 10, flags_reporter_work,
nullptr);
395 task->aux->clone_flags =
static_cast<CloneFlags>(expected_flags);
396 TaskManagerSingleton::instance().AddTask(std::move(task));
398 for (
int i = 0; i < 100 && g_flags_done.load() == 0; ++i) {
402 uint64_t reported = g_flags_value.load();
403 if (reported != expected_flags) {
405 "Flags not preserved through AddTask: got 0x{:x} expected "
407 reported, expected_flags);
413 klog::Info(
"Clone Flags Auto Completion Test: PASSED");
415 klog::Err(
"Clone Flags Auto Completion Test: FAILED");
426 klog::Info(
"===== Clone System Test Start =====");
428 g_tests_completed = 0;
431 auto& task_mgr = TaskManagerSingleton::instance();
433 auto test1 = kstd::make_unique<TaskControlBlock>(
"TestCloneProcess", 10,
434 test_clone_process,
nullptr);
435 task_mgr.AddTask(std::move(test1));
437 auto test2 = kstd::make_unique<TaskControlBlock>(
"TestCloneThread", 10,
438 test_clone_thread,
nullptr);
439 task_mgr.AddTask(std::move(test2));
441 auto test3 = kstd::make_unique<TaskControlBlock>(
442 "TestCloneParentFlag", 10, test_clone_parent_flag,
nullptr);
443 task_mgr.AddTask(std::move(test3));
445 auto test4 = kstd::make_unique<TaskControlBlock>(
446 "TestCloneFlagsAutoCompletion", 10, test_clone_flags_auto_completion,
448 task_mgr.AddTask(std::move(test4));
451 while (timeout > 0) {
453 if (g_tests_completed >= 4) {
459 EXPECT_EQ(g_tests_completed, 4,
"tests completed");
460 EXPECT_EQ(g_tests_failed, 0,
"tests failed");
462 klog::Info(
"Clone System Test Suite: COMPLETED");
auto clone_system_test() -> bool
constexpr uint64_t kFiles
共享文件描述符表
constexpr uint64_t kSighand
共享信号处理器
constexpr uint64_t kParent
保持相同父进程
constexpr uint64_t kThread
同一线程组
constexpr uint64_t kVm
共享地址空间
auto Err(etl::format_string< Args... > fmt, Args &&... args) -> void
以 ERROR 级别记录日志
auto Info(etl::format_string< Args... > fmt, Args &&... args) -> void
以 INFO 级别记录日志
auto sys_sleep(uint64_t ms) -> int
休眠指定毫秒数
auto sys_exit(int code) -> int
退出当前进程或线程
#define EXPECT_EQ(val1, val2, msg)
etl::flags< uint64_t, clone_flag::kAllMask > CloneFlags
克隆标志位