From b63c9fcc4960784cd670dc4374dd2399b7c79dd8 Mon Sep 17 00:00:00 2001 From: SirLynix Date: Tue, 23 Jan 2024 11:35:35 +0100 Subject: [PATCH] Core/Process: Add Exists function --- include/Nazara/Core/Process.hpp | 1 + src/Nazara/Core/Posix/ProcessImpl.cpp | 15 ++++++++++++++- src/Nazara/Core/Posix/ProcessImpl.hpp | 1 + src/Nazara/Core/Process.cpp | 5 +++++ src/Nazara/Core/Win32/ProcessImpl.cpp | 22 ++++++++++++++++++++++ src/Nazara/Core/Win32/ProcessImpl.hpp | 1 + 6 files changed, 44 insertions(+), 1 deletion(-) diff --git a/include/Nazara/Core/Process.hpp b/include/Nazara/Core/Process.hpp index 12d08a8d7..a9ed75cf6 100644 --- a/include/Nazara/Core/Process.hpp +++ b/include/Nazara/Core/Process.hpp @@ -29,6 +29,7 @@ namespace Nz Process& operator=(const Process&) = delete; Process& operator=(Process&&) = delete; + static Result Exists(Pid pid); static Pid GetCurrentPid(); static Result SpawnDetached(const std::filesystem::path& program, std::span arguments = {}, const std::filesystem::path& workingDirectory = {}); }; diff --git a/src/Nazara/Core/Posix/ProcessImpl.cpp b/src/Nazara/Core/Posix/ProcessImpl.cpp index 6013c0a7a..2b36dd711 100644 --- a/src/Nazara/Core/Posix/ProcessImpl.cpp +++ b/src/Nazara/Core/Posix/ProcessImpl.cpp @@ -15,6 +15,17 @@ namespace Nz::PlatformImpl { + Result CheckProcessExistence(Pid pid) + { + if (::kill(pid, 0) == 0) + return Ok(true); + + if (errno == ESRCH) + return OK(false); + + return Err(Error::GetLastSystemError()); + } + Pid GetCurrentProcessId() { return ::getpid(); @@ -34,6 +45,8 @@ namespace Nz::PlatformImpl // Double fork (see https://0xjet.github.io/3OHA/2022/04/11/post.html) // We will create a child and a grand-child process, using a pipe to retrieve the grand-child pid + // TODO: Maybe use vfork for the child process too? + // TODO: Use posix_spawn if possible instead pid_t childPid = ::fork(); if (childPid == -1) return Err("failed to create child: " + Error::GetLastSystemError()); @@ -76,7 +89,7 @@ namespace Nz::PlatformImpl ::execve(program.c_str(), argv.data(), envs); // If we get here, execve failed - // Remember we share the memory of our parent (vfork) so we need to exit using _exit() to avoid calling the parent exit handler + // Remember we share the memory of our parent (vfork) so we need to exit using _exit() to avoid calling the parent exit handlers PidOrErr err; err.pid = -1; diff --git a/src/Nazara/Core/Posix/ProcessImpl.hpp b/src/Nazara/Core/Posix/ProcessImpl.hpp index 447d99107..fb07d882a 100644 --- a/src/Nazara/Core/Posix/ProcessImpl.hpp +++ b/src/Nazara/Core/Posix/ProcessImpl.hpp @@ -12,6 +12,7 @@ namespace Nz::PlatformImpl { + Result CheckProcessExistence(Pid pid); Pid GetCurrentProcessId(); Result SpawnDetachedProcess(const std::filesystem::path& program, std::span arguments = {}, const std::filesystem::path& workingDirectory = {}); } diff --git a/src/Nazara/Core/Process.cpp b/src/Nazara/Core/Process.cpp index 3a8c53658..bb0d2a89c 100644 --- a/src/Nazara/Core/Process.cpp +++ b/src/Nazara/Core/Process.cpp @@ -16,6 +16,11 @@ namespace Nz { + Result Process::Exists(Pid pid) + { + return PlatformImpl::CheckProcessExistence(pid); + } + Pid Process::GetCurrentPid() { return PlatformImpl::GetCurrentProcessId(); diff --git a/src/Nazara/Core/Win32/ProcessImpl.cpp b/src/Nazara/Core/Win32/ProcessImpl.cpp index 5fce859d6..89554b300 100644 --- a/src/Nazara/Core/Win32/ProcessImpl.cpp +++ b/src/Nazara/Core/Win32/ProcessImpl.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -85,6 +86,27 @@ namespace Nz::PlatformImpl return commandLine; } + Result CheckProcessExistence(Pid pid) + { + HANDLE processHandle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); + if (!processHandle) + { + DWORD lastErr = ::GetLastError(); + if (lastErr == ERROR_INVALID_PARAMETER) + return Ok(false); + + return Err("failed to open process handle: " + Error::GetLastSystemError()); + } + CallOnExit releaseHandle([processHandle] { ::CloseHandle(processHandle); }); + + // Opening a handle doesn't mean the process hasn't exited (zombie processes), check if it has an exit code + DWORD exitCode; + if (!::GetExitCodeProcess(processHandle, &exitCode)) + return Err("failed to get exit code: " + Error::GetLastSystemError()); + + return Ok(exitCode == STILL_ACTIVE); + } + Pid GetCurrentProcessId() { return ::GetCurrentProcessId(); diff --git a/src/Nazara/Core/Win32/ProcessImpl.hpp b/src/Nazara/Core/Win32/ProcessImpl.hpp index 698863380..1b68fe19e 100644 --- a/src/Nazara/Core/Win32/ProcessImpl.hpp +++ b/src/Nazara/Core/Win32/ProcessImpl.hpp @@ -12,6 +12,7 @@ namespace Nz::PlatformImpl { + Result CheckProcessExistence(Pid pid); Pid GetCurrentProcessId(); Result SpawnDetachedProcess(const std::filesystem::path& program, std::span arguments = {}, const std::filesystem::path& workingDirectory = {}); }