diff options
Diffstat (limited to 'src/zenutil/process/subprocessmanager.cpp')
| -rw-r--r-- | src/zenutil/process/subprocessmanager.cpp | 193 |
1 files changed, 168 insertions, 25 deletions
diff --git a/src/zenutil/process/subprocessmanager.cpp b/src/zenutil/process/subprocessmanager.cpp index b053ac6bd..d0b912a0d 100644 --- a/src/zenutil/process/subprocessmanager.cpp +++ b/src/zenutil/process/subprocessmanager.cpp @@ -903,7 +903,11 @@ ProcessGroup::Impl::Spawn(const std::filesystem::path& Executable, Options.AssignToJob = &m_JobObject; } #else - if (m_Pgid > 0) + if (m_Pgid == 0) + { + Options.Flags |= CreateProcOptions::Flag_NewProcessGroup; + } + else { Options.ProcessGroupId = m_Pgid; } @@ -1205,7 +1209,17 @@ TEST_CASE("SubprocessManager.SpawnAndDetectExit") CallbackFired = true; }); - IoContext.run_for(5s); + { + Stopwatch Timer; + while (Timer.GetElapsedTimeMs() < 5'000) + { + IoContext.run_for(10ms); + if (CallbackFired) + { + break; + } + } + } CHECK(CallbackFired); CHECK(ReceivedExitCode == 42); @@ -1230,7 +1244,17 @@ TEST_CASE("SubprocessManager.SpawnAndDetectCleanExit") CallbackFired = true; }); - IoContext.run_for(5s); + { + Stopwatch Timer; + while (Timer.GetElapsedTimeMs() < 5'000) + { + IoContext.run_for(10ms); + if (CallbackFired) + { + break; + } + } + } CHECK(CallbackFired); CHECK(ReceivedExitCode == 0); @@ -1255,7 +1279,17 @@ TEST_CASE("SubprocessManager.StdoutCapture") ManagedProcess* Proc = Manager.Spawn(AppStub, CmdLine, Options, [&](ManagedProcess&, int) { Exited = true; }); - IoContext.run_for(5s); + { + Stopwatch Timer; + while (Timer.GetElapsedTimeMs() < 5'000) + { + IoContext.run_for(10ms); + if (Exited) + { + break; + } + } + } CHECK(Exited); std::string Captured = Proc->GetCapturedStdout(); @@ -1284,7 +1318,17 @@ TEST_CASE("SubprocessManager.StderrCapture") ManagedProcess* Proc = Manager.Spawn(AppStub, CmdLine, Options, [&](ManagedProcess&, int) { Exited = true; }); - IoContext.run_for(5s); + { + Stopwatch Timer; + while (Timer.GetElapsedTimeMs() < 5'000) + { + IoContext.run_for(10ms); + if (Exited) + { + break; + } + } + } CHECK(Exited); std::string CapturedErr = Proc->GetCapturedStderr(); @@ -1316,7 +1360,17 @@ TEST_CASE("SubprocessManager.StdoutCallback") [&](ManagedProcess&, int) { Exited = true; }, [&](ManagedProcess&, std::string_view Data) { ReceivedData.append(Data); }); - IoContext.run_for(5s); + { + Stopwatch Timer; + while (Timer.GetElapsedTimeMs() < 5'000) + { + IoContext.run_for(10ms); + if (Exited) + { + break; + } + } + } CHECK(Exited); CHECK(ReceivedData.find("callback_test") != std::string::npos); @@ -1339,8 +1393,18 @@ TEST_CASE("SubprocessManager.MetricsSampling") ManagedProcess* Proc = Manager.Spawn(AppStub, CmdLine, Options, [&](ManagedProcess&, int) { Exited = true; }); - // Run for enough time to get metrics samples - IoContext.run_for(1s); + // Poll until metrics are available + { + Stopwatch Timer; + while (Timer.GetElapsedTimeMs() < 5'000) + { + IoContext.run_for(10ms); + if (Proc->GetLatestMetrics().WorkingSetSize > 0) + { + break; + } + } + } ProcessMetrics Metrics = Proc->GetLatestMetrics(); CHECK(Metrics.WorkingSetSize > 0); @@ -1349,7 +1413,17 @@ TEST_CASE("SubprocessManager.MetricsSampling") CHECK(Snapshot.size() == 1); // Let it finish - IoContext.run_for(3s); + { + Stopwatch Timer; + while (Timer.GetElapsedTimeMs() < 10'000) + { + IoContext.run_for(10ms); + if (Exited) + { + break; + } + } + } CHECK(Exited); } @@ -1373,7 +1447,7 @@ TEST_CASE("SubprocessManager.RemoveWhileRunning") // Let it start IoContext.run_for(100ms); - // Remove without killing — callback should NOT fire after this + // Remove without killing - callback should NOT fire after this Manager.Remove(Pid); IoContext.run_for(500ms); @@ -1398,12 +1472,31 @@ TEST_CASE("SubprocessManager.KillAndWaitForExit") ManagedProcess* Proc = Manager.Spawn(AppStub, CmdLine, Options, [&](ManagedProcess&, int) { CallbackFired = true; }); // Let it start - IoContext.run_for(200ms); + { + Stopwatch Timer; + while (Timer.GetElapsedTimeMs() < 5'000) + { + IoContext.run_for(10ms); + if (Proc->IsRunning()) + { + break; + } + } + } Proc->Kill(); - IoContext.run_for(2s); - + { + Stopwatch Timer; + while (Timer.GetElapsedTimeMs() < 5'000) + { + IoContext.run_for(10ms); + if (CallbackFired) + { + break; + } + } + } CHECK(CallbackFired); } @@ -1424,7 +1517,17 @@ TEST_CASE("SubprocessManager.AdoptProcess") Manager.Adopt(ProcessHandle(Result), [&](ManagedProcess&, int ExitCode) { ReceivedExitCode = ExitCode; }); - IoContext.run_for(5s); + { + Stopwatch Timer; + while (Timer.GetElapsedTimeMs() < 5'000) + { + IoContext.run_for(10ms); + if (ReceivedExitCode != -1) + { + break; + } + } + } CHECK(ReceivedExitCode == 7); } @@ -1447,7 +1550,17 @@ TEST_CASE("SubprocessManager.UserTag") Proc->SetTag("my-worker-1"); CHECK(Proc->GetTag() == "my-worker-1"); - IoContext.run_for(5s); + { + Stopwatch Timer; + while (Timer.GetElapsedTimeMs() < 5'000) + { + IoContext.run_for(10ms); + if (!ReceivedTag.empty()) + { + break; + } + } + } CHECK(ReceivedTag == "my-worker-1"); } @@ -1477,7 +1590,17 @@ TEST_CASE("ProcessGroup.SpawnAndMembership") CHECK(Group->GetProcessCount() == 2); CHECK(Manager.GetProcessCount() == 2); - IoContext.run_for(5s); + { + Stopwatch Timer; + while (Timer.GetElapsedTimeMs() < 5'000) + { + IoContext.run_for(10ms); + if (ExitCount == 2) + { + break; + } + } + } CHECK(ExitCount == 2); } @@ -1527,7 +1650,17 @@ TEST_CASE("ProcessGroup.AggregateMetrics") Group->Spawn(AppStub, CmdLine, Options, [](ManagedProcess&, int) {}); // Wait for metrics sampling - IoContext.run_for(1s); + { + Stopwatch Timer; + while (Timer.GetElapsedTimeMs() < 5'000) + { + IoContext.run_for(10ms); + if (Group->GetAggregateMetrics().TotalWorkingSetSize > 0) + { + break; + } + } + } AggregateProcessMetrics GroupAgg = Group->GetAggregateMetrics(); CHECK(GroupAgg.ProcessCount == 2); @@ -1593,7 +1726,17 @@ TEST_CASE("ProcessGroup.MixedGroupedAndUngrouped") CHECK(Group->GetProcessCount() == 2); CHECK(Manager.GetProcessCount() == 3); - IoContext.run_for(5s); + { + Stopwatch Timer; + while (Timer.GetElapsedTimeMs() < 5'000) + { + IoContext.run_for(10ms); + if (GroupExitCount == 2 && UngroupedExitCode != -1) + { + break; + } + } + } CHECK(GroupExitCount == 2); CHECK(UngroupedExitCode == 0); @@ -1613,7 +1756,7 @@ TEST_CASE("ProcessGroup.FindGroup") TEST_CASE("SubprocessManager.StressTest" * doctest::skip()) { - // Seed for reproducibility — change to explore different orderings + // Seed for reproducibility - change to explore different orderings // // Note that while this is a stress test, it is still single-threaded @@ -1642,7 +1785,7 @@ TEST_CASE("SubprocessManager.StressTest" * doctest::skip()) // Phase 1: Spawn multiple groups with varied workloads // ======================================================================== - ZEN_INFO("StressTest: Phase 1 — spawning initial groups"); + ZEN_INFO("StressTest: Phase 1 - spawning initial groups"); constexpr int NumInitialGroups = 8; std::vector<std::string> GroupNames; @@ -1696,7 +1839,7 @@ TEST_CASE("SubprocessManager.StressTest" * doctest::skip()) // Phase 2: Randomly kill some groups, create replacements, add ungrouped // ======================================================================== - ZEN_INFO("StressTest: Phase 2 — random group kills and replacements"); + ZEN_INFO("StressTest: Phase 2 - random group kills and replacements"); constexpr int NumGroupsToKill = 3; @@ -1761,7 +1904,7 @@ TEST_CASE("SubprocessManager.StressTest" * doctest::skip()) // Phase 3: Rapid spawn/exit churn // ======================================================================== - ZEN_INFO("StressTest: Phase 3 — rapid spawn/exit churn"); + ZEN_INFO("StressTest: Phase 3 - rapid spawn/exit churn"); std::atomic<int> ChurnExitCount{0}; int TotalChurnSpawned = 0; @@ -1785,7 +1928,7 @@ TEST_CASE("SubprocessManager.StressTest" * doctest::skip()) // Brief pump to allow some exits to be processed IoContext.run_for(200ms); - // Destroy the group — any still-running processes get killed + // Destroy the group - any still-running processes get killed Manager.DestroyGroup(Name); } @@ -1795,7 +1938,7 @@ TEST_CASE("SubprocessManager.StressTest" * doctest::skip()) // Phase 4: Drain and verify // ======================================================================== - ZEN_INFO("StressTest: Phase 4 — draining remaining processes"); + ZEN_INFO("StressTest: Phase 4 - draining remaining processes"); // Check metrics were collected before we wind down AggregateProcessMetrics Agg = Manager.GetAggregateMetrics(); @@ -1826,7 +1969,7 @@ TEST_CASE("SubprocessManager.StressTest" * doctest::skip()) // (exact count is hard to predict due to killed groups, but should be > 0) CHECK(TotalExitCallbacks.load() > 0); - ZEN_INFO("StressTest: PASSED — seed={}", Seed); + ZEN_INFO("StressTest: PASSED - seed={}", Seed); } TEST_SUITE_END(); |