| 106 | } |
| 107 | |
| 108 | void test_fork_multiple(void* /*arg*/) { |
| 109 | klog::Info("=== Fork Multiple Test ==="); |
| 110 | bool passed = true; |
| 111 | |
| 112 | auto& tm = TaskManagerSingleton::instance(); |
| 113 | auto* self = tm.GetCurrentTask(); |
| 114 | g_multi_fork_done = 0; |
| 115 | |
| 116 | constexpr int kNumChildren = 4; |
| 117 | Pid child_pids[kNumChildren]; |
| 118 | |
| 119 | for (int i = 0; i < kNumChildren; ++i) { |
| 120 | auto child = kstd::make_unique<TaskControlBlock>( |
| 121 | "ForkMultiChild", 10, multi_fork_child, |
| 122 | reinterpret_cast<void*>(static_cast<uintptr_t>(i + 10))); |
| 123 | child->aux->parent_pid = self->pid; |
| 124 | auto* raw = child.get(); |
| 125 | tm.AddTask(std::move(child)); |
| 126 | child_pids[i] = raw->pid; |
| 127 | } |
| 128 | |
| 129 | for (int i = 0; i < kNumChildren; ++i) { |
| 130 | int status = 0; |
| 131 | auto result = tm.Wait(child_pids[i], &status, false, false); |
| 132 | if (!result.has_value()) { |
| 133 | klog::Err("Wait for child {} failed", i); |
| 134 | passed = false; |
| 135 | } else if (status != i + 10) { |
| 136 | klog::Err("Child {} exit code: {} (expected {})", i, status, i + 10); |
| 137 | passed = false; |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | if (g_multi_fork_done.load() != kNumChildren) { |
| 142 | klog::Err("Only {} of {} children ran", g_multi_fork_done.load(), |
| 143 | kNumChildren); |
| 144 | passed = false; |
| 145 | } |
| 146 | |
| 147 | if (!passed) { |
| 148 | g_tests_failed++; |
| 149 | } |
| 150 | g_tests_completed++; |
| 151 | klog::Info("Fork Multiple Test: {}", passed ? "PASSED" : "FAILED"); |
| 152 | sys_exit(passed ? 0 : 1); |
| 153 | } |
| 154 | |
| 155 | } // namespace |
| 156 | |