From a15de3d263a5759ca4f07aa7a2b9e6d494551150 Mon Sep 17 00:00:00 2001 From: Stefan Boberg Date: Mon, 23 Mar 2026 11:40:11 +0100 Subject: Process management improvements (#881) This PR improves process lifecycle handling and resilience across several areas: - **Reclaim stale shared-memory entries instead of exiting** (`zenserver.cpp`): When a zenserver instance fails to attach as a sponsor to an existing process (e.g. because the PID was reused by an unrelated process), the server now clears the stale shared-memory entry and proceeds with normal startup instead of calling `std::exit(1)`. - **Wait for child process exit in `Kill()` and `Terminate()` on Unix** (`process.cpp`): After sending `SIGTERM` in `Kill()`, the code now waits up to 5s for graceful shutdown (escalating to `SIGKILL` on timeout), matching the Windows behavior. `Terminate()` also waits after `SIGKILL` so the child is properly reaped and doesn't linger as a zombie clogging up the process table. - **Fix sysctl buffer race in macOS `FindProcess`** (`process.cpp`): The macOS process enumeration now retries the `sysctl` call (up to 3 attempts with 25% buffer padding) to handle the race where the process list changes between the sizing call and the data-fetching call. Also flattens the nesting and fixes the guard/free scoping. - **Terminate stale processes before integration tests** (`zenserver-test.cpp`, `test.lua`): The integration test runner now accepts a `--kill-stale-processes` flag (passed automatically by `test.lua`) that scans for and terminates any leftover `zenserver`, `zenserver-test`, and `zentest-appstub` processes from previous test runs, logging the executable name and PID of each. This addresses flaky test failures caused by stale processes from prior runs holding ports or other resources. --- src/zenutil/zenserverprocess.cpp | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) (limited to 'src/zenutil/zenserverprocess.cpp') diff --git a/src/zenutil/zenserverprocess.cpp b/src/zenutil/zenserverprocess.cpp index a2ab4c291..3993d6a32 100644 --- a/src/zenutil/zenserverprocess.cpp +++ b/src/zenutil/zenserverprocess.cpp @@ -1375,18 +1375,31 @@ ZenServerInstance::OnServerReady() const ZenServerState::ZenServerEntry* Entry = nullptr; - if (m_BasePort) + // The child process signals its ready event after writing its state entry, but under + // heavy instrumentation (e.g. sanitizers) the shared memory writes may not be immediately + // visible to this process. Retry briefly before giving up. + for (int Attempt = 0; Attempt < 10; ++Attempt) { - Entry = State.Lookup(m_BasePort); - } - else - { - State.Snapshot([&](const ZenServerState::ZenServerEntry& InEntry) { - if (InEntry.Pid == (uint32_t)m_Process.Pid()) - { - Entry = &InEntry; - } - }); + if (m_BasePort) + { + Entry = State.Lookup(m_BasePort); + } + else + { + State.Snapshot([&](const ZenServerState::ZenServerEntry& InEntry) { + if (InEntry.Pid == (uint32_t)m_Process.Pid()) + { + Entry = &InEntry; + } + }); + } + + if (Entry) + { + break; + } + + Sleep(100); } if (!Entry) -- cgit v1.2.3