diff options
Diffstat (limited to 'src/zencore/process.cpp')
| -rw-r--r-- | src/zencore/process.cpp | 137 |
1 files changed, 101 insertions, 36 deletions
diff --git a/src/zencore/process.cpp b/src/zencore/process.cpp index 88eb8af0d..f6b2cad57 100644 --- a/src/zencore/process.cpp +++ b/src/zencore/process.cpp @@ -56,7 +56,7 @@ const bool bNoZombieChildren = []() { }(); static char -GetPidStatus(int Pid) +GetPidStatus(int Pid, std::error_code& OutEc) { std::filesystem::path EntryPath = std::filesystem::path("/proc") / fmt::format("{}", Pid); std::filesystem::path StatPath = EntryPath / "stat"; @@ -80,11 +80,53 @@ GetPidStatus(int Pid) } } } + else + { + OutEc = MakeErrorCodeFromLastError(); + } } return 0; } -#endif +bool +IsZombieProcess(int pid, std::error_code& OutEc) +{ + char Status = GetPidStatus(pid, OutEc); + if (OutEc) + { + return false; + } + if (Status == 'Z' || Status == 0) + { + return true; + } + return false; +} + +#endif // ZEN_PLATFORM_LINUX + +#if ZEN_PLATFORM_MAC +bool +IsZombieProcess(int pid, std::error_code& OutEc) +{ + struct kinfo_proc Info; + int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; + size_t InfoSize = sizeof Info; + + int Res = sysctl(Mib, 4, &Info, &InfoSize, NULL, 0); + if (Res != 0) + { + OutEc = MakeErrorCodeFromLastError(); + return false; + } + if (Info.kp_proc.p_stat == SZOMB) + { + // Zombie process + return true; + } + return false; +} +#endif // ZEN_PLATFORM_MAC ProcessHandle::ProcessHandle() = default; @@ -220,7 +262,7 @@ ProcessHandle::Reset() } bool -ProcessHandle::Wait(int TimeoutMs) +ProcessHandle::Wait(int TimeoutMs, std::error_code& OutEc) { using namespace std::literals; @@ -237,20 +279,39 @@ ProcessHandle::Wait(int TimeoutMs) case WAIT_TIMEOUT: return false; + case WAIT_ABANDONED_0: + return true; + case WAIT_FAILED: break; } -#elif ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC + + OutEc = MakeErrorCodeFromLastError(); + + return false; +#endif // ZEN_PLATFORM_WINDOWS + +#if ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC const int SleepMs = 20; timespec SleepTime = {0, SleepMs * 1000 * 1000}; for (int SleepedTimeMS = 0;; SleepedTimeMS += SleepMs) { int WaitState = 0; - waitpid(m_Pid, &WaitState, WNOHANG | WCONTINUED | WUNTRACED); + if (waitpid(m_Pid, &WaitState, WNOHANG | WCONTINUED | WUNTRACED) != -1) + { + if (WIFEXITED(WaitState)) + { + m_ExitCode = WEXITSTATUS(WaitState); + } + } - if (WIFEXITED(WaitState)) + if (!IsProcessRunning(m_Pid, OutEc)) + { + return true; + } + else if (OutEc) { - m_ExitCode = WEXITSTATUS(WaitState); + return false; } if (kill(m_Pid, 0) < 0) @@ -260,7 +321,13 @@ ProcessHandle::Wait(int TimeoutMs) { return true; } - ThrowSystemError(static_cast<uint32_t>(LastError), "Process::Wait kill failed"sv); + OutEc = MakeErrorCode(LastError); + return false; + } + else if (IsZombieProcess(m_Pid, OutEc)) + { + ZEN_INFO("Found process {} in zombie state, treating as not running", m_Pid); + return true; } if (TimeoutMs >= 0 && SleepedTimeMS >= TimeoutMs) @@ -270,10 +337,23 @@ ProcessHandle::Wait(int TimeoutMs) nanosleep(&SleepTime, nullptr); } -#endif + return false; +#endif // ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC +} - // What might go wrong here, and what is meaningful to act on? - ThrowLastError("Process::Wait failed"sv); +bool +ProcessHandle::Wait(int TimeoutMs) +{ + std::error_code Ec; + if (Wait(TimeoutMs, Ec) && !Ec) + { + return true; + } + else if (Ec) + { + throw std::system_error(Ec, std::string("Process::Wait kill failed")); + } + return false; } int @@ -740,34 +820,16 @@ IsProcessRunning(int pid, std::error_code& OutEc) int Res = kill(pid_t(pid), 0); if (Res == 0) { -# if ZEN_PLATFORM_MAC - struct kinfo_proc Info; - int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; - size_t InfoSize = sizeof Info; - - int Res = sysctl(Mib, 4, &Info, &InfoSize, NULL, 0); - if (Res != 0) - { - int Error = errno; - OutEc = MakeErrorCode(Error); - return false; - } - ZEN_INFO("Found process {} with status {}", pid, (int)Info.kp_proc.p_stat); - if (Info.kp_proc.p_stat == SZOMB) + if (IsZombieProcess(pid, OutEc)) { - // Zombie process + ZEN_INFO("Found process {} in zombie state, treating as not running", pid); return false; } - return true; -# endif // ZEN_PLATFORM_MAC -# if ZEN_PLATFORM_LINUX - char Status = GetPidStatus(pid); - if (Status == 'Z' || Status == 0) + if (OutEc) { return false; } return true; -# endif // ZEN_PLATFORM_LINUX } int Error = errno; if (Error == ESRCH) // No such process @@ -969,11 +1031,14 @@ FindProcess(const std::filesystem::path& ExecutableImage, ProcessHandle& OutHand { if (EntryPath == ExecutableImage) { - char Status = GetPidStatus(Pid); - if (Status && (Status != 'Z')) + char Status = GetPidStatus(Pid, Ec); + if (!Ec) { - OutHandle.Initialize(Pid, Ec); - return Ec; + if (Status && (Status != 'Z')) + { + OutHandle.Initialize(Pid, Ec); + return Ec; + } } } } |