diff options
| author | Nikolai Nechaev <nikolay_nechaev@mail.ru> | 2025-09-24 02:32:48 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-23 19:32:48 +0200 |
| commit | 29b103c3762d01c9711aba33985f27869238143d (patch) | |
| tree | da6a4fba108d13a5624558b9824f9ae58124e931 /hyprtester/src/tests/main/exec.cpp | |
| parent | 70a7047ee175d2e7fca1575d50a3738ac40fd2c6 (diff) | |
exec: Spawn processes as direct children (#11735)
* exec: Spawn processes as direct children
Spawn processes as children rather than grandchildren.
This way, spawned processes may track Hyprland's state
by watching their parent, either directly or indirectly
(e.g., Linux's `PR_SET_PDEATH_SIG`).
Fixes #11728
* tests/exec: Add the test on process spawning
Add a test that ensures that:
- A spawned process remains a direct child of Hyprland;
- Upon termination, the process does not become a zombie.
Diffstat (limited to 'hyprtester/src/tests/main/exec.cpp')
| -rw-r--r-- | hyprtester/src/tests/main/exec.cpp | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/hyprtester/src/tests/main/exec.cpp b/hyprtester/src/tests/main/exec.cpp new file mode 100644 index 00000000..a475ac0d --- /dev/null +++ b/hyprtester/src/tests/main/exec.cpp @@ -0,0 +1,64 @@ +#include "tests.hpp" +#include "../../shared.hpp" +#include "../../hyprctlCompat.hpp" +#include <chrono> +#include <thread> +#include <hyprutils/os/Process.hpp> +#include <hyprutils/memory/WeakPtr.hpp> +#include "../shared.hpp" + +static int ret = 0; + +using namespace Hyprutils::OS; +using namespace Hyprutils::Memory; + +#define UP CUniquePointer +#define SP CSharedPointer + +static std::string execAndGet(const std::string& cmd) { + CProcess proc("/bin/sh", {"-c", cmd}); + + if (!proc.runSync()) { + return "error"; + } + + return proc.stdOut(); +} + +static bool test() { + NLog::log("{}Testing process spawning", Colors::GREEN); + + // Note: POSIX sleep does not support fractional seconds, so + // can't sleep for less than 1 second. + OK(getFromSocket("/dispatch exec sleep 1")); + + // Ensure that sleep is our child + const std::string sleepPidS = execAndGet("pgrep sleep"); + pid_t sleepPid; + try { + sleepPid = std::stoull(sleepPidS); + } catch (...) { + NLog::log("{}Sleep was not spawned or several sleeps are running: pgrep returned '{}'", Colors::RED, sleepPidS); + return false; + } + + const std::string sleepParentComm = execAndGet("cat \"/proc/$(ps -o ppid:1= -p " + sleepPidS + ")/comm\""); + NLog::log("{}Expecting that sleep's parent is Hyprland", Colors::YELLOW); + EXPECT_CONTAINS(sleepParentComm, "Hyprland"); + + std::this_thread::sleep_for(std::chrono::seconds(1)); + + // Ensure that sleep did not become a zombie + EXPECT(Tests::processAlive(sleepPid), false); + + // kill all + NLog::log("{}Killing all windows", Colors::YELLOW); + Tests::killAllWindows(); + + NLog::log("{}Expecting 0 windows", Colors::YELLOW); + EXPECT(Tests::windowCount(), 0); + + return !ret; +} + +REGISTER_TEST_FN(test) |
