| 129 | } |
| 130 | |
| 131 | void test_runner_entry(void* /*arg*/) { |
| 132 | auto& task_mgr = TaskManagerSingleton::instance(); |
| 133 | auto* runner = task_mgr.GetCurrentTask(); |
| 134 | |
| 135 | // Phase 2: 为每个非 SMP 测试创建独立线程,建立父子关系 |
| 136 | int thread_test_count = 0; |
| 137 | |
| 138 | for (size_t i = 0; i < kTestCount; ++i) { |
| 139 | if (test_cases[i].is_smp_test) { |
| 140 | continue; |
| 141 | } |
| 142 | |
| 143 | auto task = kstd::make_unique<TaskControlBlock>( |
| 144 | test_cases[i].name, 10, test_thread_entry, reinterpret_cast<void*>(i)); |
| 145 | |
| 146 | // Wait() requires parent-child relationship to collect exit status |
| 147 | task->aux->parent_pid = runner->pid; |
| 148 | task->aux->pgid = runner->aux->pgid; |
| 149 | |
| 150 | // Save raw pointer: pid is assigned inside AddTask() by AllocatePid(), |
| 151 | // so we must read it *after* the call (unique_ptr is moved). |
| 152 | auto* task_ptr = task.get(); |
| 153 | test_results[i].status = TestThreadStatus::kRunning; |
| 154 | |
| 155 | task_mgr.AddTask(std::move(task)); |
| 156 | test_results[i].pid = task_ptr->pid; |
| 157 | thread_test_count++; |
| 158 | } |
| 159 | |
| 160 | klog::Info("[RUNNER] Spawned {} test threads, collecting via Wait()...", |
| 161 | thread_test_count); |
| 162 | |
| 163 | // Phase 3: 通过 Wait() 收集所有测试线程的退出状态 |
| 164 | int collected = 0; |
| 165 | constexpr int kMaxWaitRetries = 1200; // 1200 * 50ms = 60s 超时 |
| 166 | int retries = 0; |
| 167 | |
| 168 | while (collected < thread_test_count && retries < kMaxWaitRetries) { |
| 169 | int status = 0; |
| 170 | auto wait_result = |
| 171 | task_mgr.Wait(static_cast<Pid>(-1), &status, true, false); |
| 172 | |
| 173 | if (wait_result.has_value() && wait_result.value() > 0) { |
| 174 | Pid exited_pid = wait_result.value(); |
| 175 | |
| 176 | bool is_test_thread = false; |
| 177 | for (size_t i = 0; i < kTestCount; ++i) { |
| 178 | if (test_results[i].pid == static_cast<int64_t>(exited_pid)) { |
| 179 | test_results[i].exit_code = status; |
| 180 | test_results[i].status = (status == 0) ? TestThreadStatus::kPassed |
| 181 | : TestThreadStatus::kFailed; |
| 182 | |
| 183 | klog::Info("[RUNNER] Collected: {} (pid={}, exit_code={}) — {}", |
| 184 | test_cases[i].name, exited_pid, status, |
| 185 | (status == 0) ? "PASS" : "FAIL"); |
| 186 | is_test_thread = true; |
| 187 | break; |
| 188 | } |
nothing calls this directly
no test coverage detected