From 32b09d20caa7d2168ec73bc8f267de0ab664db0e Mon Sep 17 00:00:00 2001 From: Jan Erik Hanssen Date: Sun, 1 Mar 2015 22:53:44 -0800 Subject: [PATCH] Fix race in Process for very short-lived processes --- rct/Process.cpp | 56 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/rct/Process.cpp b/rct/Process.cpp index 523de12..8c657c1 100644 --- a/rct/Process.cpp +++ b/rct/Process.cpp @@ -7,6 +7,7 @@ #include "StopWatch.h" #include "Thread.h" #include +#include #include #include #include @@ -24,8 +25,9 @@ class ProcessThread : public Thread public: static void installProcessHandler(); static void addPid(pid_t pid, Process* process, bool async); - static void removePid(pid_t pid); static void shutdown(); + static void setPending(int pending); + protected: void run(); @@ -43,6 +45,8 @@ class ProcessThread : public Thread static int sProcessPipe[2]; static std::mutex sProcessMutex; + static int sPending; + static std::unordered_map sPendingPids; struct ProcessData { @@ -55,6 +59,8 @@ class ProcessThread : public Thread ProcessThread* ProcessThread::sProcessThread = 0; int ProcessThread::sProcessPipe[2]; std::mutex ProcessThread::sProcessMutex; +int ProcessThread::sPending = 0; +std::unordered_map ProcessThread::sPendingPids; std::map ProcessThread::sProcesses; class ProcessThreadKiller @@ -75,16 +81,42 @@ ProcessThread::ProcessThread() SocketClient::setFlags(sProcessPipe[1], O_NONBLOCK, F_GETFL, F_SETFL); } -void ProcessThread::addPid(pid_t pid, Process* process, bool async) +void ProcessThread::setPending(int pending) { std::lock_guard lock(sProcessMutex); - sProcesses[pid] = { process, async ? EventLoop::eventLoop() : EventLoop::SharedPtr() }; + sPending += pending; + assert(sPending >= 0); + if (!pending) + sPendingPids.clear(); } -void ProcessThread::removePid(pid_t pid) +void ProcessThread::addPid(pid_t pid, Process* process, bool async) { std::lock_guard lock(sProcessMutex); - sProcesses.erase(pid); + sPending -= 1; + + if (!sPendingPids.empty()) { + // we have to check + auto it = sPendingPids.find(pid); + if (it != sPendingPids.end()) { + // fire the signal now + const int ret = it->second; + if (async) { + EventLoop::eventLoop()->callLater([process, ret]() { process->finish(ret); }); + } else { + process->finish(ret); + } + sPendingPids.erase(it); + if (!sPending) + sPendingPids.clear(); + return; + } + } + + sProcesses[pid] = { process, async ? EventLoop::eventLoop() : EventLoop::SharedPtr() }; + + if (!sPending) + sPendingPids.clear(); } void ProcessThread::run() @@ -136,7 +168,12 @@ void ProcessThread::run() } lock.lock(); } else { - error() << "couldn't find process for pid" << p; + if (sPending) { + assert(sPendingPids.find(p) == sPendingPids.end()); + sPendingPids[p] = ret; + } else { + error() << "couldn't find process for pid" << p; + } } } } while (!done); @@ -333,10 +370,15 @@ Process::ExecState Process::startInternal(const Path &command, const List