Commit 3034d901 authored by mdempsky@chromium.org's avatar mdempsky@chromium.org

Cleanup WaitpidWithTimeout

This CL gives WaitpidWithTimeout() an API more similar to waitpid();
i.e., it returns the success state via the return value, and the
process's termination status via an out-parameter.  It also avoids
assuming that "status == -1" is an invalid status code, as POSIX makes
no guarantees about the representation of status values.

Lastly (and my original motivation), the code now avoids unnecessarily
relying on non-portable waitpid() behavior.  POSIX arguably requires
waitpid() to *not* modify the status value if it returns 0, but at least
OpenBSD still modifies status in this case, which then triggers a DCHECK
failure in base_unittests.

TEST="base_unittests --gtest_filter=ProcessUtilTest.DelayedTermination" on OpenBSD

Review URL: https://codereview.chromium.org/319703007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@275983 0039d316-1c4b-4281-b951-d872f2087c98
parent bdd1b22e
...@@ -22,11 +22,11 @@ namespace base { ...@@ -22,11 +22,11 @@ namespace base {
namespace { namespace {
int WaitpidWithTimeout(ProcessHandle handle, bool WaitpidWithTimeout(ProcessHandle handle,
int64 wait_milliseconds, int* status,
bool* success) { base::TimeDelta wait) {
// This POSIX version of this function only guarantees that we wait no less // This POSIX version of this function only guarantees that we wait no less
// than |wait_milliseconds| for the process to exit. The child process may // than |wait| for the process to exit. The child process may
// exit sometime before the timeout has ended but we may still block for up // exit sometime before the timeout has ended but we may still block for up
// to 256 milliseconds after the fact. // to 256 milliseconds after the fact.
// //
...@@ -37,7 +37,7 @@ int WaitpidWithTimeout(ProcessHandle handle, ...@@ -37,7 +37,7 @@ int WaitpidWithTimeout(ProcessHandle handle,
// affect other parts of the application and would be difficult to debug. // affect other parts of the application and would be difficult to debug.
// //
// Our strategy is to call waitpid() once up front to check if the process // Our strategy is to call waitpid() once up front to check if the process
// has already exited, otherwise to loop for wait_milliseconds, sleeping for // has already exited, otherwise to loop for |wait|, sleeping for
// at most 256 milliseconds each time using usleep() and then calling // at most 256 milliseconds each time using usleep() and then calling
// waitpid(). The amount of time we sleep starts out at 1 milliseconds, and // waitpid(). The amount of time we sleep starts out at 1 milliseconds, and
// we double it every 4 sleep cycles. // we double it every 4 sleep cycles.
...@@ -48,15 +48,18 @@ int WaitpidWithTimeout(ProcessHandle handle, ...@@ -48,15 +48,18 @@ int WaitpidWithTimeout(ProcessHandle handle,
// //
// This function is used primarily for unit tests, if we want to use it in // This function is used primarily for unit tests, if we want to use it in
// the application itself it would probably be best to examine other routes. // the application itself it would probably be best to examine other routes.
int status = -1;
pid_t ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); if (wait.InMilliseconds() == base::kNoTimeout) {
return HANDLE_EINTR(waitpid(handle, status, 0)) > 0;
}
pid_t ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG));
static const int64 kMaxSleepInMicroseconds = 1 << 18; // ~256 milliseconds. static const int64 kMaxSleepInMicroseconds = 1 << 18; // ~256 milliseconds.
int64 max_sleep_time_usecs = 1 << 10; // ~1 milliseconds. int64 max_sleep_time_usecs = 1 << 10; // ~1 milliseconds.
int64 double_sleep_time = 0; int64 double_sleep_time = 0;
// If the process hasn't exited yet, then sleep and try again. // If the process hasn't exited yet, then sleep and try again.
TimeTicks wakeup_time = TimeTicks::Now() + TimeTicks wakeup_time = TimeTicks::Now() + wait;
TimeDelta::FromMilliseconds(wait_milliseconds);
while (ret_pid == 0) { while (ret_pid == 0) {
TimeTicks now = TimeTicks::Now(); TimeTicks now = TimeTicks::Now();
if (now > wakeup_time) if (now > wakeup_time)
...@@ -70,7 +73,7 @@ int WaitpidWithTimeout(ProcessHandle handle, ...@@ -70,7 +73,7 @@ int WaitpidWithTimeout(ProcessHandle handle,
// usleep() will return 0 and set errno to EINTR on receipt of a signal // usleep() will return 0 and set errno to EINTR on receipt of a signal
// such as SIGCHLD. // such as SIGCHLD.
usleep(sleep_time_usecs); usleep(sleep_time_usecs);
ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG));
if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) && if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) &&
(double_sleep_time++ % 4 == 0)) { (double_sleep_time++ % 4 == 0)) {
...@@ -78,10 +81,7 @@ int WaitpidWithTimeout(ProcessHandle handle, ...@@ -78,10 +81,7 @@ int WaitpidWithTimeout(ProcessHandle handle,
} }
} }
if (success) return ret_pid > 0;
*success = (ret_pid != -1);
return status;
} }
TerminationStatus GetTerminationStatusImpl(ProcessHandle handle, TerminationStatus GetTerminationStatusImpl(ProcessHandle handle,
...@@ -226,12 +226,8 @@ bool WaitForExitCode(ProcessHandle handle, int* exit_code) { ...@@ -226,12 +226,8 @@ bool WaitForExitCode(ProcessHandle handle, int* exit_code) {
bool WaitForExitCodeWithTimeout(ProcessHandle handle, bool WaitForExitCodeWithTimeout(ProcessHandle handle,
int* exit_code, int* exit_code,
base::TimeDelta timeout) { base::TimeDelta timeout) {
bool waitpid_success = false; int status;
int status = WaitpidWithTimeout(handle, timeout.InMilliseconds(), if (!WaitpidWithTimeout(handle, &status, timeout))
&waitpid_success);
if (status == -1)
return false;
if (!waitpid_success)
return false; return false;
if (WIFSIGNALED(status)) { if (WIFSIGNALED(status)) {
*exit_code = -1; *exit_code = -1;
...@@ -369,21 +365,10 @@ bool WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) { ...@@ -369,21 +365,10 @@ bool WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) {
#endif // OS_MACOSX #endif // OS_MACOSX
} }
bool waitpid_success; int status;
int status = -1; if (!WaitpidWithTimeout(handle, &status, wait))
if (wait.InMilliseconds() == base::kNoTimeout) {
waitpid_success = (HANDLE_EINTR(waitpid(handle, &status, 0)) != -1);
} else {
status = WaitpidWithTimeout(
handle, wait.InMilliseconds(), &waitpid_success);
}
if (status != -1) {
DCHECK(waitpid_success);
return WIFEXITED(status);
} else {
return false; return false;
} return WIFEXITED(status);
} }
bool CleanupProcesses(const FilePath::StringType& executable_name, bool CleanupProcesses(const FilePath::StringType& executable_name,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment