diff options
Diffstat (limited to 'src/zencore')
| -rw-r--r-- | src/zencore/process.cpp | 85 | ||||
| -rw-r--r-- | src/zencore/thread.cpp | 12 |
2 files changed, 69 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(); diff --git a/src/zencore/thread.cpp b/src/zencore/thread.cpp index f74791333..067e66c0d 100644 --- a/src/zencore/thread.cpp +++ b/src/zencore/thread.cpp @@ -503,6 +503,18 @@ NamedMutex::~NamedMutex() if (m_MutexHandle) { int Inner = int(intptr_t(m_MutexHandle)); + + // Remove the backing file before releasing the lock so that new callers + // of Create()/Exists() won't find a stale entry. Other processes that + // already have the file open still hold valid fds (unlink only removes + // the directory entry; the inode lives until the last fd is closed). + std::error_code Ec; + std::filesystem::path Name = PathFromHandle((void*)(intptr_t(Inner)), Ec); + if (!Ec) + { + unlink(Name.c_str()); + } + flock(Inner, LOCK_UN); close(Inner); } |