aboutsummaryrefslogtreecommitdiff
path: root/src/zencore/process.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2026-03-24 15:47:23 +0100
committerGitHub Enterprise <[email protected]>2026-03-24 15:47:23 +0100
commit21c2abb1bde697c31bee562465cb986a0429a299 (patch)
tree3734d235e79a8fbed307ae5c248936d356553b61 /src/zencore/process.cpp
parentv5.7.25 hotpatch (#874) (diff)
downloadzen-21c2abb1bde697c31bee562465cb986a0429a299.tar.xz
zen-21c2abb1bde697c31bee562465cb986a0429a299.zip
Subprocess Manager (#889)
Adds a `SubprocessManager` for managing child processes with ASIO-integrated async exit detection, stdout/stderr pipe capture, and periodic metrics sampling. Also introduces `ProcessGroup` for OS-backed process grouping (Windows JobObjects / POSIX process groups). ### SubprocessManager - Async process exit detection using platform-native mechanisms (Windows `object_handle`, Linux `pidfd_open`, macOS `kqueue EVFILT_PROC`) — no polling - Stdout/stderr capture via async pipe readers with per-process or default callbacks - Periodic round-robin metrics sampling (CPU, memory) across managed processes - Spawn, adopt, remove, kill, and enumerate managed processes ### ProcessGroup - OS-level process grouping: Windows JobObject (kill-on-close guarantee), POSIX `setpgid` (bulk signal delivery) - Atomic group kill via `TerminateJobObject` (Windows) or `kill(-pgid, sig)` (POSIX) - Per-group aggregate metrics and enumeration ### ProcessHandle improvements - Added explicit constructors from `int` (pid) and `void*` (native handle) - Added move constructor and move assignment operator ### ProcessMetricsTracker - Cross-platform process metrics (CPU time, working set, page faults) via `QueryProcessMetrics()` - ASIO timer-driven periodic sampling with configurable interval and batch size - Aggregate metrics across tracked processes ### Other changes - Fixed `zentest-appstub` writing a spurious `Versions` file to cwd on every invocation
Diffstat (limited to 'src/zencore/process.cpp')
-rw-r--r--src/zencore/process.cpp53
1 files changed, 53 insertions, 0 deletions
diff --git a/src/zencore/process.cpp b/src/zencore/process.cpp
index dcb8b2422..e7baa3f8e 100644
--- a/src/zencore/process.cpp
+++ b/src/zencore/process.cpp
@@ -277,6 +277,46 @@ CreateStdoutPipe(StdoutPipeHandles& OutPipe)
ProcessHandle::ProcessHandle() = default;
+ProcessHandle::ProcessHandle(int Pid)
+{
+ Initialize(Pid);
+}
+
+#if ZEN_PLATFORM_WINDOWS
+ProcessHandle::ProcessHandle(void* NativeHandle)
+{
+ Initialize(NativeHandle);
+}
+#endif
+
+ProcessHandle::ProcessHandle(ProcessHandle&& Other) noexcept
+: m_ProcessHandle(Other.m_ProcessHandle)
+, m_Pid(Other.m_Pid)
+#if ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC
+, m_ExitCode(Other.m_ExitCode)
+#endif
+{
+ Other.m_ProcessHandle = nullptr;
+ Other.m_Pid = 0;
+}
+
+ProcessHandle&
+ProcessHandle::operator=(ProcessHandle&& Other) noexcept
+{
+ if (this != &Other)
+ {
+ Reset();
+ m_ProcessHandle = Other.m_ProcessHandle;
+ m_Pid = Other.m_Pid;
+#if ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC
+ m_ExitCode = Other.m_ExitCode;
+#endif
+ Other.m_ProcessHandle = nullptr;
+ Other.m_Pid = 0;
+ }
+ return *this;
+}
+
#if ZEN_PLATFORM_WINDOWS
void
ProcessHandle::Initialize(void* ProcessHandle)
@@ -720,6 +760,10 @@ CreateProcNormal(const std::filesystem::path& Executable, std::string_view Comma
}
if (Options.Flags & CreateProcOptions::Flag_NoConsole)
{
+ CreationFlags |= DETACHED_PROCESS;
+ }
+ if (Options.Flags & CreateProcOptions::Flag_NoWindow)
+ {
CreationFlags |= CREATE_NO_WINDOW;
}
if (Options.Flags & CreateProcOptions::Flag_Windows_NewProcessGroup)
@@ -930,6 +974,10 @@ CreateProcUnelevated(const std::filesystem::path& Executable, std::string_view C
}
if (Options.Flags & CreateProcOptions::Flag_NoConsole)
{
+ CreateProcFlags |= DETACHED_PROCESS;
+ }
+ if (Options.Flags & CreateProcOptions::Flag_NoWindow)
+ {
CreateProcFlags |= CREATE_NO_WINDOW;
}
if (AssignToJob)
@@ -1070,6 +1118,11 @@ CreateProc(const std::filesystem::path& Executable, std::string_view CommandLine
}
}
+ if (Options.ProcessGroupId > 0)
+ {
+ setpgid(0, Options.ProcessGroupId);
+ }
+
for (const auto& [Key, Value] : Options.Environment)
{
setenv(Key.c_str(), Value.c_str(), 1);