GH #2689: Added tryWait() into Process and ProcessHandle. Handle kill()-ed UNIX process exit codes.

This commit is contained in:
Günter Obiltschnig
2020-01-22 08:23:36 +01:00
parent 5f0e0a0374
commit 924cdf235c
12 changed files with 187 additions and 95 deletions

View File

@@ -21,7 +21,7 @@
#include "Poco/Foundation.h"
#if defined(POCO_OS_FAMILY_WINDOWS)
#if defined(POCO_OS_FAMILY_WINDOWS)
#if defined(_WIN32_WCE)
#include "Process_WINCE.h"
#else
@@ -66,6 +66,11 @@ public:
/// Waits for the process to terminate
/// and returns the exit code of the process.
int tryWait() const;
/// Checks that process is terminated
/// and returns the exit code of the process.
/// If the process is still running, returns -1.
protected:
ProcessHandle(ProcessHandleImpl* pImpl);
@@ -211,6 +216,10 @@ public:
/// Waits for the process specified by handle to terminate
/// and returns the exit code of the process.
static int tryWait(const ProcessHandle& handle);
/// Checks that process is finished and returns the exit code of the
/// process. If the process is still running, returns -1.
static bool isRunning(const ProcessHandle& handle);
/// check if the process specified by handle is running or not
///

View File

@@ -36,10 +36,11 @@ class Foundation_API ProcessHandleImpl: public RefCountedObject
public:
ProcessHandleImpl(pid_t pid);
~ProcessHandleImpl();
pid_t id() const;
int wait() const;
int tryWait() const;
private:
pid_t _pid;
};
@@ -51,15 +52,15 @@ public:
typedef pid_t PIDImpl;
typedef std::vector<std::string> ArgsImpl;
typedef std::map<std::string, std::string> EnvImpl;
static PIDImpl idImpl();
static void timesImpl(long& userTime, long& kernelTime);
static ProcessHandleImpl* launchImpl(
const std::string& command,
const ArgsImpl& args,
const std::string& command,
const ArgsImpl& args,
const std::string& initialDirectory,
Pipe* inPipe,
Pipe* outPipe,
Pipe* inPipe,
Pipe* outPipe,
Pipe* errPipe,
const EnvImpl& env);
static void killImpl(ProcessHandleImpl& handle);
@@ -70,11 +71,11 @@ public:
private:
static ProcessHandleImpl* launchByForkExecImpl(
const std::string& command,
const ArgsImpl& args,
const std::string& command,
const ArgsImpl& args,
const std::string& initialDirectory,
Pipe* inPipe,
Pipe* outPipe,
Pipe* inPipe,
Pipe* outPipe,
Pipe* errPipe,
const EnvImpl& env);
};

View File

@@ -38,10 +38,11 @@ class Foundation_API ProcessHandleImpl: public RefCountedObject
public:
ProcessHandleImpl(int pid);
~ProcessHandleImpl();
int id() const;
int wait() const;
int tryWait() const;
private:
int _pid;
};
@@ -53,15 +54,15 @@ public:
typedef int PIDImpl;
typedef std::vector<std::string> ArgsImpl;
typedef std::map<std::string, std::string> EnvImpl;
static PIDImpl idImpl();
static void timesImpl(long& userTime, long& kernelTime);
static ProcessHandleImpl* launchImpl(
const std::string& command,
const ArgsImpl& args,
const std::string& command,
const ArgsImpl& args,
const std::string& initialDirectory,
Pipe* inPipe,
Pipe* outPipe,
Pipe* inPipe,
Pipe* outPipe,
Pipe* errPipe,
const EnvImpl& env);
static void killImpl(ProcessHandleImpl& handle);

View File

@@ -36,16 +36,17 @@ class Foundation_API ProcessHandleImpl: public RefCountedObject
public:
ProcessHandleImpl(HANDLE _hProcess, UInt32 pid);
~ProcessHandleImpl();
UInt32 id() const;
HANDLE process() const;
int wait() const;
int tryWait() const;
void closeHandle();
private:
HANDLE _hProcess;
UInt32 _pid;
ProcessHandleImpl(const ProcessHandleImpl&);
ProcessHandleImpl& operator = (const ProcessHandleImpl&);
};
@@ -57,15 +58,15 @@ public:
typedef UInt32 PIDImpl;
typedef std::vector<std::string> ArgsImpl;
typedef std::map<std::string, std::string> EnvImpl;
static PIDImpl idImpl();
static void timesImpl(long& userTime, long& kernelTime);
static ProcessHandleImpl* launchImpl(
const std::string& command,
const ArgsImpl& args,
const std::string& command,
const ArgsImpl& args,
const std::string& initialDirectory,
Pipe* inPipe,
Pipe* outPipe,
Pipe* inPipe,
Pipe* outPipe,
Pipe* errPipe,
const EnvImpl& env);
static void killImpl(ProcessHandleImpl& handle);

View File

@@ -36,10 +36,11 @@ class Foundation_API ProcessHandleImpl: public RefCountedObject
public:
ProcessHandleImpl(HANDLE _hProcess, UInt32 pid);
~ProcessHandleImpl();
UInt32 id() const;
HANDLE process() const;
int wait() const;
int tryWait() const;
void closeHandle();
private:
@@ -57,15 +58,15 @@ public:
typedef UInt32 PIDImpl;
typedef std::vector<std::string> ArgsImpl;
typedef std::map<std::string, std::string> EnvImpl;
static PIDImpl idImpl();
static void timesImpl(long& userTime, long& kernelTime);
static ProcessHandleImpl* launchImpl(
const std::string& command,
const ArgsImpl& args,
const std::string& command,
const ArgsImpl& args,
const std::string& initialDirectory,
Pipe* inPipe,
Pipe* outPipe,
Pipe* inPipe,
Pipe* outPipe,
Pipe* errPipe,
const EnvImpl& env);
static void killImpl(ProcessHandleImpl& handle);

View File

@@ -36,10 +36,11 @@ class Foundation_API ProcessHandleImpl: public RefCountedObject
public:
ProcessHandleImpl(HANDLE _hProcess, UInt32 pid);
~ProcessHandleImpl();
UInt32 id() const;
HANDLE process() const;
int wait() const;
int tryWait() const;
void closeHandle();
private:
@@ -57,15 +58,15 @@ public:
typedef UInt32 PIDImpl;
typedef std::vector<std::string> ArgsImpl;
typedef std::map<std::string, std::string> EnvImpl;
static PIDImpl idImpl();
static void timesImpl(long& userTime, long& kernelTime);
static ProcessHandleImpl* launchImpl(
const std::string& command,
const ArgsImpl& args,
const std::string& command,
const ArgsImpl& args,
const std::string& initialDirectory,
Pipe* inPipe,
Pipe* outPipe,
Pipe* inPipe,
Pipe* outPipe,
Pipe* errPipe,
const EnvImpl& env);
static void killImpl(ProcessHandleImpl& handle);

View File

@@ -110,6 +110,12 @@ int ProcessHandle::wait() const
}
int ProcessHandle::tryWait() const
{
return _pImpl->tryWait();
}
//
// Process
//
@@ -166,6 +172,12 @@ int Process::wait(const ProcessHandle& handle)
}
int Process::tryWait(const ProcessHandle& handle)
{
return handle.tryWait();
}
void Process::kill(ProcessHandle& handle)
{
killImpl(*handle._pImpl);

View File

@@ -66,7 +66,31 @@ int ProcessHandleImpl::wait() const
while (rc < 0 && errno == EINTR);
if (rc != _pid)
throw SystemException("Cannot wait for process", NumberFormatter::format(_pid));
return WEXITSTATUS(status);
if (WIFEXITED(status)) // normal termination
return WEXITSTATUS(status);
else // termination by a signal
return 256 + WTERMSIG(status);
}
int ProcessHandleImpl::tryWait() const
{
int status;
int rc;
do
{
rc = waitpid(_pid, &status, WNOHANG);
}
while (rc < 0 && errno == EINTR);
if (rc == 0)
return -1;
if (rc != _pid)
throw SystemException("Cannot wait for process", NumberFormatter::format(_pid));
if (WIFEXITED(status)) // normal termination
return WEXITSTATUS(status);
else // termination by a signal
return 256 + WTERMSIG(status);
}
@@ -97,7 +121,7 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg
char** argv = new char*[args.size() + 2];
int i = 0;
argv[i++] = const_cast<char*>(command.c_str());
for (const auto& a: args)
for (const auto& a: args)
argv[i++] = const_cast<char*>(a.c_str());
argv[i] = NULL;
struct inheritance inherit;
@@ -107,7 +131,7 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg
fdmap[0] = inPipe ? inPipe->readHandle() : 0;
fdmap[1] = outPipe ? outPipe->writeHandle() : 1;
fdmap[2] = errPipe ? errPipe->writeHandle() : 2;
char** envPtr = 0;
std::vector<char> envChars;
std::vector<char*> envPtrs;
@@ -125,10 +149,10 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg
envPtrs.push_back(0);
envPtr = &envPtrs[0];
}
int pid = spawn(command.c_str(), 3, fdmap, &inherit, argv, envPtr);
delete [] argv;
if (pid == -1)
if (pid == -1)
throw SystemException("cannot spawn", command);
if (inPipe) inPipe->close(Pipe::CLOSE_READ);
@@ -155,18 +179,18 @@ ProcessHandleImpl* ProcessImpl::launchByForkExecImpl(const std::string& command,
std::vector<char*> argv(args.size() + 2);
int i = 0;
argv[i++] = const_cast<char*>(command.c_str());
for (const auto& a: args)
for (const auto& a: args)
{
argv[i++] = const_cast<char*>(a.c_str());
}
argv[i] = NULL;
const char* pInitialDirectory = initialDirectory.empty() ? 0 : initialDirectory.c_str();
int pid = fork();
if (pid < 0)
{
throw SystemException("Cannot fork process for", command);
throw SystemException("Cannot fork process for", command);
}
else if (pid == 0)
{
@@ -247,19 +271,19 @@ bool ProcessImpl::isRunningImpl(const ProcessHandleImpl& handle)
}
bool ProcessImpl::isRunningImpl(PIDImpl pid)
bool ProcessImpl::isRunningImpl(PIDImpl pid)
{
if (kill(pid, 0) == 0)
if (kill(pid, 0) == 0)
{
return true;
}
else
}
else
{
return false;
}
}
void ProcessImpl::requestTerminationImpl(PIDImpl pid)
{
if (kill(pid, SIGINT) != 0)

View File

@@ -45,6 +45,12 @@ int ProcessHandleImpl::wait() const
}
int ProcessHandleImpl::tryWait() const
{
throw Poco::NotImplementedException("Process::tryWait()");
}
//
// ProcessImpl
//
@@ -79,13 +85,13 @@ void ProcessImpl::killImpl(PIDImpl pid)
}
bool ProcessImpl::isRunningImpl(const ProcessHandleImpl& handle)
bool ProcessImpl::isRunningImpl(const ProcessHandleImpl& handle)
{
throw Poco::NotImplementedException("Process::is_running()");
}
bool ProcessImpl::isRunningImpl(PIDImpl pid)
bool ProcessImpl::isRunningImpl(PIDImpl pid)
{
throw Poco::NotImplementedException("Process::is_running()");
}

View File

@@ -74,6 +74,18 @@ int ProcessHandleImpl::wait() const
}
int ProcessHandleImpl::tryWait() const
{
DWORD exitCode;
if (GetExitCodeProcess(_hProcess, &exitCode) == 0)
throw SystemException("Cannot get exit code for process", NumberFormatter::format(_pid));
if (exitCode == STILL_ACTIVE)
return -1;
else
return exitCode;
}
//
// ProcessImpl
//
@@ -99,7 +111,7 @@ void ProcessImpl::timesImpl(long& userTime, long& kernelTime)
time.LowPart = ftUser.dwLowDateTime;
time.HighPart = ftUser.dwHighDateTime;
userTime = long(time.QuadPart / 10000000L);
}
}
else
{
userTime = kernelTime = -1;
@@ -137,12 +149,12 @@ static std::string escapeArg(const std::string& arg)
{
quotedArg.append(2 * backslashCount, '\\');
break;
}
}
else if ('"' == *it)
{
quotedArg.append(2 * backslashCount + 1, '\\');
quotedArg.push_back('"');
}
}
else
{
quotedArg.append(backslashCount, '\\');
@@ -151,7 +163,7 @@ static std::string escapeArg(const std::string& arg)
}
quotedArg.push_back('"');
return quotedArg;
}
}
else
{
return arg;
@@ -185,12 +197,12 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg
DuplicateHandle(hProc, inPipe->readHandle(), hProc, &startupInfo.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
mustInheritHandles = true;
inPipe->close(Pipe::CLOSE_READ);
}
}
else if (GetStdHandle(STD_INPUT_HANDLE))
{
DuplicateHandle(hProc, GetStdHandle(STD_INPUT_HANDLE), hProc, &startupInfo.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
mustInheritHandles = true;
}
}
else
{
startupInfo.hStdInput = 0;
@@ -200,12 +212,12 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg
{
DuplicateHandle(hProc, outPipe->writeHandle(), hProc, &startupInfo.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
mustInheritHandles = true;
}
}
else if (GetStdHandle(STD_OUTPUT_HANDLE))
{
DuplicateHandle(hProc, GetStdHandle(STD_OUTPUT_HANDLE), hProc, &startupInfo.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
mustInheritHandles = true;
}
}
else
{
startupInfo.hStdOutput = 0;
@@ -214,12 +226,12 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg
{
DuplicateHandle(hProc, errPipe->writeHandle(), hProc, &startupInfo.hStdError, 0, TRUE, DUPLICATE_SAME_ACCESS);
mustInheritHandles = true;
}
}
else if (GetStdHandle(STD_ERROR_HANDLE))
{
DuplicateHandle(hProc, GetStdHandle(STD_ERROR_HANDLE), hProc, &startupInfo.hStdError, 0, TRUE, DUPLICATE_SAME_ACCESS);
mustInheritHandles = true;
}
}
else
{
startupInfo.hStdError = 0;
@@ -263,7 +275,7 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg
{
CloseHandle(processInfo.hThread);
return new ProcessHandleImpl(processInfo.hProcess, processInfo.dwProcessId);
}
}
else throw SystemException("Cannot launch process", command);
}
@@ -292,14 +304,14 @@ void ProcessImpl::killImpl(PIDImpl pid)
throw SystemException("cannot kill process");
}
CloseHandle(hProc);
}
}
else
{
switch (GetLastError())
{
case ERROR_ACCESS_DENIED:
throw NoPermissionException("cannot kill process");
case ERROR_NOT_FOUND:
case ERROR_NOT_FOUND:
throw NotFoundException("cannot kill process");
case ERROR_INVALID_PARAMETER:
throw NotFoundException("cannot kill process");

View File

@@ -78,6 +78,18 @@ int ProcessHandleImpl::wait() const
}
int ProcessHandleImpl::tryWait() const
{
DWORD exitCode;
if (GetExitCodeProcess(_hProcess, &exitCode) == 0)
throw SystemException("Cannot get exit code for process", NumberFormatter::format(_pid));
if (exitCode == STILL_ACTIVE)
return -1;
else
return exitCode;
}
//
// ProcessImpl
//
@@ -103,7 +115,7 @@ void ProcessImpl::timesImpl(long& userTime, long& kernelTime)
time.LowPart = ftUser.dwLowDateTime;
time.HighPart = ftUser.dwHighDateTime;
userTime = long(time.QuadPart / 10000000L);
}
}
else
{
userTime = kernelTime = -1;
@@ -141,12 +153,12 @@ static std::string escapeArg(const std::string& arg)
{
quotedArg.append(2 * backslashCount, '\\');
break;
}
}
else if ('"' == *it)
{
quotedArg.append(2 * backslashCount + 1, '\\');
quotedArg.push_back('"');
}
}
else
{
quotedArg.append(backslashCount, '\\');
@@ -155,7 +167,7 @@ static std::string escapeArg(const std::string& arg)
}
quotedArg.push_back('"');
return quotedArg;
}
}
else
{
return arg;
@@ -205,12 +217,12 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg
DuplicateHandle(hProc, inPipe->readHandle(), hProc, &startupInfo.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
mustInheritHandles = true;
inPipe->close(Pipe::CLOSE_READ);
}
}
else if (GetStdHandle(STD_INPUT_HANDLE))
{
DuplicateHandle(hProc, GetStdHandle(STD_INPUT_HANDLE), hProc, &startupInfo.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
mustInheritHandles = true;
}
}
else
{
startupInfo.hStdInput = 0;
@@ -220,12 +232,12 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg
{
DuplicateHandle(hProc, outPipe->writeHandle(), hProc, &startupInfo.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
mustInheritHandles = true;
}
}
else if (GetStdHandle(STD_OUTPUT_HANDLE))
{
DuplicateHandle(hProc, GetStdHandle(STD_OUTPUT_HANDLE), hProc, &startupInfo.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
mustInheritHandles = true;
}
}
else
{
startupInfo.hStdOutput = 0;
@@ -234,12 +246,12 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg
{
DuplicateHandle(hProc, errPipe->writeHandle(), hProc, &startupInfo.hStdError, 0, TRUE, DUPLICATE_SAME_ACCESS);
mustInheritHandles = true;
}
}
else if (GetStdHandle(STD_ERROR_HANDLE))
{
DuplicateHandle(hProc, GetStdHandle(STD_ERROR_HANDLE), hProc, &startupInfo.hStdError, 0, TRUE, DUPLICATE_SAME_ACCESS);
mustInheritHandles = true;
}
}
else
{
startupInfo.hStdError = 0;
@@ -285,7 +297,7 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg
{
CloseHandle(processInfo.hThread);
return new ProcessHandleImpl(processInfo.hProcess, processInfo.dwProcessId);
}
}
else throw SystemException("Cannot launch process", command);
}
@@ -314,14 +326,14 @@ void ProcessImpl::killImpl(PIDImpl pid)
throw SystemException("cannot kill process");
}
CloseHandle(hProc);
}
}
else
{
switch (GetLastError())
{
case ERROR_ACCESS_DENIED:
throw NoPermissionException("cannot kill process");
case ERROR_NOT_FOUND:
case ERROR_NOT_FOUND:
throw NotFoundException("cannot kill process");
case ERROR_INVALID_PARAMETER:
throw NotFoundException("cannot kill process");

View File

@@ -73,12 +73,24 @@ int ProcessHandleImpl::wait() const
}
int ProcessHandleImpl::tryWait() const
{
DWORD exitCode;
if (GetExitCodeProcess(_hProcess, &exitCode) == 0)
throw SystemException("Cannot get exit code for process", NumberFormatter::format(_pid));
if (exitCode == STILL_ACTIVE)
return -1;
else
return exitCode;
}
//
// ProcessImpl
//
ProcessImpl::PIDImpl ProcessImpl::idImpl()
{
return GetCurrentProcessId();
return GetCurrentProcessId();
}
@@ -110,28 +122,28 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg
{
std::wstring ucommand;
UnicodeConverter::toUTF16(command, ucommand);
std::string commandLine;
for (ArgsImpl::const_iterator it = args.begin(); it != args.end(); ++it)
{
if (it != args.begin()) commandLine.append(" ");
commandLine.append(*it);
}
}
std::wstring ucommandLine;
UnicodeConverter::toUTF16(commandLine, ucommandLine);
PROCESS_INFORMATION processInfo;
BOOL rc = CreateProcessW(
ucommand.c_str(),
const_cast<wchar_t*>(ucommandLine.c_str()),
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
NULL/*&startupInfo*/,
ucommand.c_str(),
const_cast<wchar_t*>(ucommandLine.c_str()),
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
NULL/*&startupInfo*/,
&processInfo
);
@@ -146,7 +158,7 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg
void ProcessImpl::killImpl(ProcessHandleImpl& handle)
{
if (handle.process())
if (handle.process())
{
if (TerminateProcess(handle.process(), 0) == 0)
{
@@ -176,7 +188,7 @@ void ProcessImpl::killImpl(PIDImpl pid)
{
case ERROR_ACCESS_DENIED:
throw NoPermissionException("cannot kill process");
case ERROR_NOT_FOUND:
case ERROR_NOT_FOUND:
throw NotFoundException("cannot kill process");
default:
throw SystemException("cannot kill process");
@@ -185,7 +197,7 @@ void ProcessImpl::killImpl(PIDImpl pid)
}
bool ProcessImpl::isRunningImpl(const ProcessHandleImpl& handle)
bool ProcessImpl::isRunningImpl(const ProcessHandleImpl& handle)
{
bool result = true;
DWORD exitCode;
@@ -195,7 +207,7 @@ bool ProcessImpl::isRunningImpl(const ProcessHandleImpl& handle)
}
bool ProcessImpl::isRunningImpl(PIDImpl pid)
bool ProcessImpl::isRunningImpl(PIDImpl pid)
{
HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
bool result = true;