Skip to content

Commit 483d0a7

Browse files
committed
enh(Process): Changes to detect defunct process more reliable.
1 parent 7ee01c1 commit 483d0a7

File tree

3 files changed

+50
-40
lines changed

3 files changed

+50
-40
lines changed

Foundation/include/Poco/Process_UNIX.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,10 @@ class Foundation_API ProcessHandleImpl: public RefCountedObject
4545
int wait() const;
4646
int wait(int options) const;
4747
int tryWait() const;
48+
bool isRunning() const;
4849

4950
private:
51+
static int statusToExitCode(int status);
5052
const std::atomic<pid_t> _pid;
5153
mutable Event _event;
5254
mutable std::optional<std::atomic<int>> _status;

Foundation/src/Process_UNIX.cpp

Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,21 @@ pid_t ProcessHandleImpl::id() const
5757
}
5858

5959

60+
int ProcessHandleImpl::statusToExitCode(int status)
61+
{
62+
if (WIFEXITED(status))
63+
return WEXITSTATUS(status);
64+
else
65+
return -WTERMSIG(status);
66+
}
67+
68+
6069
int ProcessHandleImpl::wait() const
6170
{
6271
if (wait(0) != _pid)
6372
throw SystemException("Cannot wait for process", NumberFormatter::format(_pid));
6473

65-
return WEXITSTATUS(_status.value());
74+
return statusToExitCode(_status.value());
6675
}
6776

6877

@@ -73,7 +82,7 @@ int ProcessHandleImpl::wait(int options) const
7382
int rc;
7483
do
7584
{
76-
rc = waitpid(_pid, &status, options);
85+
rc = ::waitpid(_pid, &status, options);
7786
}
7887
while (rc < 0 && errno == EINTR);
7988
if (rc == _pid)
@@ -83,10 +92,9 @@ int ProcessHandleImpl::wait(int options) const
8392
}
8493
else if (rc < 0 && errno == ECHILD)
8594
{
86-
// Looks like another thread was lucky and it should update the status for us shortly
87-
_event.wait();
88-
89-
if (_status.has_value())
95+
// Another thread reaped the process; wait for it to update the status.
96+
// Use a timeout to prevent hanging indefinitely if something goes wrong.
97+
if (_event.tryWait(5000) && _status.has_value())
9098
{
9199
rc = _pid;
92100
}
@@ -98,21 +106,20 @@ int ProcessHandleImpl::wait(int options) const
98106

99107
int ProcessHandleImpl::tryWait() const
100108
{
101-
int status;
102-
int rc;
103-
do
104-
{
105-
rc = waitpid(_pid, &status, WNOHANG);
106-
}
107-
while (rc < 0 && errno == EINTR);
109+
int rc = wait(WNOHANG);
108110
if (rc == 0)
109111
return -1;
110112
if (rc != _pid)
111113
throw SystemException("Cannot wait for process", NumberFormatter::format(_pid));
112-
if (WIFEXITED(status)) // normal termination
113-
return WEXITSTATUS(status);
114-
else // termination by a signal
115-
return 256 + WTERMSIG(status);
114+
return statusToExitCode(_status.value());
115+
}
116+
117+
118+
bool ProcessHandleImpl::isRunning() const
119+
{
120+
if (_status.has_value())
121+
return false;
122+
return wait(WNOHANG) == 0;
116123
}
117124

118125

@@ -121,14 +128,14 @@ int ProcessHandleImpl::tryWait() const
121128
//
122129
ProcessImpl::PIDImpl ProcessImpl::idImpl()
123130
{
124-
return getpid();
131+
return ::getpid();
125132
}
126133

127134

128135
void ProcessImpl::timesImpl(long& userTime, long& kernelTime)
129136
{
130137
struct rusage usage;
131-
getrusage(RUSAGE_SELF, &usage);
138+
::getrusage(RUSAGE_SELF, &usage);
132139
userTime = usage.ru_utime.tv_sec;
133140
kernelTime = usage.ru_stime.tv_sec;
134141
}
@@ -137,7 +144,7 @@ void ProcessImpl::timesImpl(long& userTime, long& kernelTime)
137144
void ProcessImpl::timesMicrosecondsImpl(Poco::Int64& userTime, Poco::Int64& kernelTime)
138145
{
139146
struct rusage usage;
140-
getrusage(RUSAGE_SELF, &usage);
147+
::getrusage(RUSAGE_SELF, &usage);
141148
userTime = static_cast<Poco::Int64>(usage.ru_utime.tv_sec)*1000000 + usage.ru_utime.tv_usec;
142149
kernelTime = static_cast<Poco::Int64>(usage.ru_stime.tv_sec)*1000000 + usage.ru_stime.tv_usec;
143150
}
@@ -186,17 +193,17 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg
186193
envPtr = &envPtrs[0];
187194
}
188195

189-
int pid = spawn(command.c_str(), 3, fdmap, &inherit, argv, envPtr);
196+
int pid = ::spawn(command.c_str(), 3, fdmap, &inherit, argv, envPtr);
190197
delete [] argv;
191198
if (pid == -1)
192199
throw SystemException("cannot spawn", command);
193200

194201
if (inPipe) inPipe->close(Pipe::CLOSE_READ);
195-
if (options & PROCESS_CLOSE_STDIN) close(STDIN_FILENO);
202+
if (options & PROCESS_CLOSE_STDIN) ::close(STDIN_FILENO);
196203
if (outPipe) outPipe->close(Pipe::CLOSE_WRITE);
197-
if (options & PROCESS_CLOSE_STDOUT) close(STDOUT_FILENO);
204+
if (options & PROCESS_CLOSE_STDOUT) ::close(STDOUT_FILENO);
198205
if (errPipe) errPipe->close(Pipe::CLOSE_WRITE);
199-
if (options & PROCESS_CLOSE_STDERR) close(STDERR_FILENO);
206+
if (options & PROCESS_CLOSE_STDERR) ::close(STDERR_FILENO);
200207
return new ProcessHandleImpl(pid);
201208
}
202209
else
@@ -234,7 +241,7 @@ ProcessHandleImpl* ProcessImpl::launchByForkExecImpl(const std::string& command,
234241

235242
const char* pInitialDirectory = initialDirectory.empty() ? nullptr : initialDirectory.c_str();
236243

237-
int pid = fork();
244+
int pid = ::fork();
238245
if (pid < 0)
239246
{
240247
throw SystemException("Cannot fork process for", command);
@@ -243,7 +250,7 @@ ProcessHandleImpl* ProcessImpl::launchByForkExecImpl(const std::string& command,
243250
{
244251
if (pInitialDirectory)
245252
{
246-
if (chdir(pInitialDirectory) != 0)
253+
if (::chdir(pInitialDirectory) != 0)
247254
{
248255
break;
249256
}
@@ -253,33 +260,33 @@ ProcessHandleImpl* ProcessImpl::launchByForkExecImpl(const std::string& command,
253260
char* p = &envChars[0];
254261
while (*p)
255262
{
256-
putenv(p);
263+
::putenv(p);
257264
while (*p) ++p;
258265
++p;
259266
}
260267

261268
// setup redirection
262269
if (inPipe)
263270
{
264-
dup2(inPipe->readHandle(), STDIN_FILENO);
271+
::dup2(inPipe->readHandle(), STDIN_FILENO);
265272
inPipe->close(Pipe::CLOSE_BOTH);
266273
}
267-
if (options & PROCESS_CLOSE_STDIN) close(STDIN_FILENO);
274+
if (options & PROCESS_CLOSE_STDIN) ::close(STDIN_FILENO);
268275

269276
// outPipe and errPipe may be the same, so we dup first and close later
270-
if (outPipe) dup2(outPipe->writeHandle(), STDOUT_FILENO);
271-
if (errPipe) dup2(errPipe->writeHandle(), STDERR_FILENO);
277+
if (outPipe) ::dup2(outPipe->writeHandle(), STDOUT_FILENO);
278+
if (errPipe) ::dup2(errPipe->writeHandle(), STDERR_FILENO);
272279
if (outPipe) outPipe->close(Pipe::CLOSE_BOTH);
273-
if (options & PROCESS_CLOSE_STDOUT) close(STDOUT_FILENO);
280+
if (options & PROCESS_CLOSE_STDOUT) ::close(STDOUT_FILENO);
274281
if (errPipe) errPipe->close(Pipe::CLOSE_BOTH);
275-
if (options & PROCESS_CLOSE_STDERR) close(STDERR_FILENO);
282+
if (options & PROCESS_CLOSE_STDERR) ::close(STDERR_FILENO);
276283
// close all open file descriptors other than stdin, stdout, stderr
277-
long fdMax = sysconf(_SC_OPEN_MAX);
284+
long fdMax = ::sysconf(_SC_OPEN_MAX);
278285
// on some systems, sysconf(_SC_OPEN_MAX) returns a ridiculously high number
279286
if (fdMax > CLOSE_FD_MAX) fdMax = CLOSE_FD_MAX;
280287
for (long j = 3; j < fdMax; ++j)
281288
{
282-
close(j);
289+
::close(j);
283290
}
284291

285292
// Create a new process group so the entire tree can be signaled.
@@ -289,7 +296,7 @@ ProcessHandleImpl* ProcessImpl::launchByForkExecImpl(const std::string& command,
289296
_exit(PROCESS_EXIT_SETPGID_FAILED);
290297
}
291298

292-
execvp(argv[0], &argv[0]);
299+
::execvp(argv[0], &argv[0]);
293300
break;
294301
}
295302

@@ -322,7 +329,7 @@ void ProcessImpl::killImpl(ProcessHandleImpl& handle)
322329

323330
void ProcessImpl::killImpl(PIDImpl pid)
324331
{
325-
if (kill(pid, SIGKILL) != 0)
332+
if (::kill(pid, SIGKILL) != 0)
326333
{
327334
switch (errno)
328335
{
@@ -339,13 +346,13 @@ void ProcessImpl::killImpl(PIDImpl pid)
339346

340347
bool ProcessImpl::isRunningImpl(const ProcessHandleImpl& handle)
341348
{
342-
return isRunningImpl(handle.id());
349+
return handle.isRunning();
343350
}
344351

345352

346353
bool ProcessImpl::isRunningImpl(PIDImpl pid)
347354
{
348-
if (kill(pid, 0) == 0)
355+
if (::kill(pid, 0) == 0)
349356
{
350357
return true;
351358
}
@@ -358,7 +365,7 @@ bool ProcessImpl::isRunningImpl(PIDImpl pid)
358365

359366
void ProcessImpl::requestTerminationImpl(PIDImpl pid)
360367
{
361-
if (kill(pid, SIGINT) != 0)
368+
if (::kill(pid, SIGINT) != 0)
362369
{
363370
switch (errno)
364371
{

Foundation/testsuite/src/ProcessTest.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "Poco/Environment.h"
2020
#include "Poco/ProcessOptions.h"
2121
#include "Poco/Thread.h"
22+
#include <csignal>
2223
#include <iostream>
2324

2425

0 commit comments

Comments
 (0)