aboutsummaryrefslogtreecommitdiff
path: root/src/zencore/process.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zencore/process.cpp')
-rw-r--r--src/zencore/process.cpp137
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;
+ }
}
}
}