From 5f2de9df054cf54c15949e4207ad80bddfc59419 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 24 Jul 2018 13:28:41 +0100 Subject: [PATCH] Use sigaction to create Qt-compatible handler to reap zombie processes --- renderdoc/os/posix/posix_process.cpp | 52 ++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/renderdoc/os/posix/posix_process.cpp b/renderdoc/os/posix/posix_process.cpp index 62f7770b4..90f3a9f9d 100644 --- a/renderdoc/os/posix/posix_process.cpp +++ b/renderdoc/os/posix/posix_process.cpp @@ -26,12 +26,14 @@ #include #include #include +#include #include #include #include #include #include #include "api/app/renderdoc_app.h" +#include "common/threading.h" #include "os/os_specific.h" #include "strings/string_utils.h" @@ -39,6 +41,51 @@ char **GetCurrentEnvironment(); int GetIdentPort(pid_t childPid); +Threading::CriticalSection zombieLock; +struct sigaction old_action; + +static void ZombieWaiter(int signum, siginfo_t *handler_info, void *handler_context) +{ + // save errno + int saved_errno = errno; + + // call the old handler + if(old_action.sa_handler != SIG_IGN && old_action.sa_handler != SIG_DFL) + { + if(old_action.sa_flags & SA_SIGINFO) + old_action.sa_sigaction(signum, handler_info, handler_context); + else + old_action.sa_handler(signum); + } + + // wait for any children, but don't block (hang). Continue waiting while there are children to + // wait for. + while(waitpid(pid_t(-1), NULL, WNOHANG) > 0) + { + } + + // restore errno + errno = saved_errno; +} + +static void SetupZombieCollectionHandler() +{ + SCOPED_LOCK(zombieLock); + + static bool installed = false; + if(installed) + return; + + installed = true; + + struct sigaction new_action = {}; + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = SA_NOCLDSTOP | SA_SIGINFO | SA_RESTART; + new_action.sa_sigaction = &ZombieWaiter; + + sigaction(SIGCHLD, &new_action, &old_action); +} + namespace FileIO { void ReleaseFDAfterFork(); @@ -368,8 +415,9 @@ static pid_t RunProcess(const char *app, const char *workingDir, const char *cmd // don't fork if we didn't find anything to execute. if(!appPath.empty()) { - // don't care about child processes, just ignore them - // signal(SIGCHLD, SIG_IGN); + // we have to handle child processes with wait otherwise they become zombies. Unfortunately Qt + // breaks if we just ignore the signal and let the system reap them. + SetupZombieCollectionHandler(); childPid = fork(); if(childPid == 0)