diff options
Diffstat (limited to 'src/zencore/process.cpp')
| -rw-r--r-- | src/zencore/process.cpp | 85 |
1 files changed, 57 insertions, 28 deletions
diff --git a/src/zencore/process.cpp b/src/zencore/process.cpp index 8a91ab287..47289a37b 100644 --- a/src/zencore/process.cpp +++ b/src/zencore/process.cpp @@ -397,6 +397,17 @@ ProcessHandle::Kill() return false; } } + + // Wait for the process to exit after SIGTERM, matching the Windows path + // which waits up to 5 seconds for graceful shutdown. Without this wait + // the child becomes a zombie and may hold resources (e.g. TCP ports). + std::error_code Ec; + if (!Wait(5000, Ec)) + { + // Graceful shutdown timed out — force-kill + kill(pid_t(m_Pid), SIGKILL); + Wait(1000, Ec); + } #endif Reset(); @@ -435,6 +446,11 @@ ProcessHandle::Terminate(int ExitCode) return false; } } + + // Wait for the process to be reaped after SIGKILL so it doesn't linger + // as a zombie holding resources (e.g. TCP ports). + std::error_code Ec; + Wait(5000, Ec); #endif Reset(); return true; @@ -1648,47 +1664,60 @@ FindProcess(const std::filesystem::path& ExecutableImage, ProcessHandle& OutHand return MakeErrorCodeFromLastError(); #endif // ZEN_PLATFORM_WINDOWS #if ZEN_PLATFORM_MAC - int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}; - size_t BufferSize = 0; - - struct kinfo_proc* Processes = nullptr; - uint32_t ProcCount = 0; + int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}; const pid_t ThisProcessId = getpid(); - if (sysctl(Mib, 4, NULL, &BufferSize, NULL, 0) != -1 && BufferSize > 0) + // The process list can change between the sizing sysctl call and the data sysctl call. + // Retry with padding to handle this race. + struct kinfo_proc* Processes = nullptr; + size_t BufferSize = 0; + bool Fetched = false; + auto _ = MakeGuard([&]() { free(Processes); }); + + for (int Attempt = 0; Attempt < 3; Attempt++) { - struct kinfo_proc* Processes = (struct kinfo_proc*)malloc(BufferSize); - auto _ = MakeGuard([&]() { free(Processes); }); - if (sysctl(Mib, 4, Processes, &BufferSize, NULL, 0) != -1) + if (sysctl(Mib, 4, nullptr, &BufferSize, nullptr, 0) == -1 || BufferSize == 0) + { + break; + } + BufferSize += BufferSize / 4; + free(Processes); + Processes = (struct kinfo_proc*)malloc(BufferSize); + if (sysctl(Mib, 4, Processes, &BufferSize, nullptr, 0) != -1) { - ProcCount = (uint32_t)(BufferSize / sizeof(struct kinfo_proc)); - char Buffer[PROC_PIDPATHINFO_MAXSIZE]; - for (uint32_t ProcIndex = 0; ProcIndex < ProcCount; ProcIndex++) + Fetched = true; + break; + } + } + + if (!Fetched) + { + return MakeErrorCodeFromLastError(); + } + + uint32_t ProcCount = (uint32_t)(BufferSize / sizeof(struct kinfo_proc)); + for (uint32_t ProcIndex = 0; ProcIndex < ProcCount; ProcIndex++) + { + pid_t Pid = Processes[ProcIndex].kp_proc.p_pid; + if (IncludeSelf || (Pid != ThisProcessId)) + { + std::error_code Ec; + std::filesystem::path EntryPath = GetProcessExecutablePath(Pid, Ec); + if (!Ec) { - pid_t Pid = Processes[ProcIndex].kp_proc.p_pid; - if (IncludeSelf || (Pid != ThisProcessId)) + if (EntryPath == ExecutableImage) { - std::error_code Ec; - std::filesystem::path EntryPath = GetProcessExecutablePath(Pid, Ec); - if (!Ec) + if (Processes[ProcIndex].kp_proc.p_stat != SZOMB) { - if (EntryPath == ExecutableImage) - { - if (Processes[ProcIndex].kp_proc.p_stat != SZOMB) - { - OutHandle.Initialize(Pid, Ec); - return Ec; - } - } + OutHandle.Initialize(Pid, Ec); + return Ec; } - Ec.clear(); } } - return {}; } } - return MakeErrorCodeFromLastError(); + return {}; #endif // ZEN_PLATFORM_MAC #if ZEN_PLATFORM_LINUX const pid_t ThisProcessId = getpid(); |