diff --git a/renderdoc/os/posix/posix_process.cpp b/renderdoc/os/posix/posix_process.cpp index 90f3a9f9d..d698b2e91 100644 --- a/renderdoc/os/posix/posix_process.cpp +++ b/renderdoc/os/posix/posix_process.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "api/app/renderdoc_app.h" #include "common/threading.h" #include "os/os_specific.h" @@ -43,6 +44,7 @@ int GetIdentPort(pid_t childPid); Threading::CriticalSection zombieLock; struct sigaction old_action; +std::set children; static void ZombieWaiter(int signum, siginfo_t *handler_info, void *handler_context) { @@ -58,10 +60,28 @@ static void ZombieWaiter(int signum, siginfo_t *handler_info, void *handler_cont 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) + std::vector waitedChildren; + std::set localChildren; { + SCOPED_LOCK(zombieLock); + localChildren = children; + } + + // wait for any children, but don't block (hang). We must only wait for our own PIDs as waiting + // for any other handler's PIDs (like Qt's) might lose the one chance they have to wait for them + // themselves. + for(pid_t pid : localChildren) + { + // remember the child PIDs that we successfully waited on + if(waitpid(pid, NULL, WNOHANG) > 0) + waitedChildren.push_back(pid); + } + + // remove any waited children from the list + { + SCOPED_LOCK(zombieLock); + for(pid_t pid : waitedChildren) + children.erase(pid); } // restore errno @@ -439,6 +459,12 @@ static pid_t RunProcess(const char *app, const char *workingDir, const char *cmd fprintf(stderr, "exec failed\n"); _exit(1); } + else + { + // remember this PID so we can wait on it later + SCOPED_LOCK(zombieLock); + children.insert(childPid); + } } if(stdoutPipe)