Allow for process termination when polling with isRunning

On *NIX, one needs to call `waitpid()` in order for process to exit the
zombie state. If one uses `Process::isRunning()` to emulate non-blocking
wait for child process termination, process will stay zombie and function
will always return true.

This commit changes `Process::isRunning()` to call `waitpid()` with
`WNOHANG` instead of using `kill()` when checking for child process (i.e.
the one we have ProcessHandle for), which allows for process termination.
Additional trickery with mutex and event is needed to prevent exceptions
when `Process::isRunning()` and/or `Process::wait()` is called concurrently
on the same handle from different threads.

Fixes #1097.
This commit is contained in:
Mike Gelfand
2016-01-09 02:16:55 +03:00
parent 279ea9d0e2
commit 0425866486
4 changed files with 82 additions and 11 deletions

View File

@@ -16,6 +16,7 @@
#include "Poco/Process.h"
#include "Poco/Pipe.h"
#include "Poco/PipeStream.h"
#include "Poco/Thread.h"
#include <csignal>
@@ -176,6 +177,27 @@ void ProcessTest::testIsRunning()
}
void ProcessTest::testIsRunningAllowsForTermination()
{
#if !defined(_WIN32_WCE)
std::string name("TestApp");
std::string cmd;
#if defined(POCO_OS_FAMILY_UNIX)
cmd = "./";
cmd += name;
#else
cmd = name;
#endif
std::vector<std::string> args;
ProcessHandle ph = Process::launch(cmd, args, 0, 0, 0);
while (Process::isRunning(ph))
Poco::Thread::sleep(100);
#endif // !defined(_WIN32_WCE)
}
void ProcessTest::testSignalExitCode()
{
#if defined(POCO_OS_FAMILY_UNIX)
@@ -213,6 +235,7 @@ CppUnit::Test* ProcessTest::suite()
CppUnit_addTest(pSuite, ProcessTest, testLaunchRedirectOut);
CppUnit_addTest(pSuite, ProcessTest, testLaunchEnv);
CppUnit_addTest(pSuite, ProcessTest, testIsRunning);
CppUnit_addTest(pSuite, ProcessTest, testIsRunningAllowsForTermination);
CppUnit_addTest(pSuite, ProcessTest, testSignalExitCode);
return pSuite;