Index: base/process/process_posix.cc |
diff --git a/base/process/process_posix.cc b/base/process/process_posix.cc |
index a083123b75fe2cbda0c34f18bf6e39fa3ad3b58c..a7d16f87304f2b38953c9ca9fe42f47e6c0c7634 100644 |
--- a/base/process/process_posix.cc |
+++ b/base/process/process_posix.cc |
@@ -11,6 +11,7 @@ |
#include "base/logging.h" |
#include "base/posix/eintr_wrapper.h" |
#include "base/process/kill.h" |
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h" |
#if defined(OS_MACOSX) |
#include <sys/event.h> |
@@ -210,6 +211,9 @@ namespace base { |
Process::Process(ProcessHandle handle) : process_(handle) { |
} |
+Process::~Process() { |
+} |
+ |
Process::Process(RValue other) |
: process_(other.object->process_) { |
other.object->Close(); |
@@ -287,14 +291,59 @@ void Process::Close() { |
// end up w/ a zombie when it does finally exit. |
} |
-bool Process::Terminate(int result_code, bool wait) const { |
+#if !defined(OS_NACL_NONSFI) |
+bool Process::Terminate(int exit_code, bool wait) const { |
// result_code isn't supportable. |
DCHECK(IsValid()); |
- // We don't wait here. It's the responsibility of other code to reap the |
- // child. |
- // TODO(rvargas) crbug/417532: Move the implementation here. |
- return KillProcess(process_, result_code, wait); |
+ DCHECK_GT(process_, 1); |
+ bool result = kill(process_, SIGTERM) == 0; |
+ if (result && wait) { |
+ int tries = 60; |
+ |
+ if (RunningOnValgrind()) { |
+ // Wait for some extra time when running under Valgrind since the child |
+ // processes may take some time doing leak checking. |
+ tries *= 2; |
+ } |
+ |
+ unsigned sleep_ms = 4; |
+ |
+ // The process may not end immediately due to pending I/O |
+ bool exited = false; |
+ while (tries-- > 0) { |
+ pid_t pid = HANDLE_EINTR(waitpid(process_, NULL, WNOHANG)); |
+ if (pid == process_) { |
+ exited = true; |
+ break; |
+ } |
+ if (pid == -1) { |
+ if (errno == ECHILD) { |
+ // The wait may fail with ECHILD if another process also waited for |
+ // the same pid, causing the process state to get cleaned up. |
+ exited = true; |
+ break; |
+ } |
+ DPLOG(ERROR) << "Error waiting for process " << process_; |
+ } |
+ |
+ usleep(sleep_ms * 1000); |
+ const unsigned kMaxSleepMs = 1000; |
+ if (sleep_ms < kMaxSleepMs) |
+ sleep_ms *= 2; |
+ } |
+ |
+ // If we're waiting and the child hasn't died by now, force it |
+ // with a SIGKILL. |
+ if (!exited) |
+ result = kill(process_, SIGKILL) == 0; |
+ } |
+ |
+ if (!result) |
+ DPLOG(ERROR) << "Unable to terminate process " << process_; |
+ |
+ return result; |
} |
+#endif // !defined(OS_NACL_NONSFI) |
bool Process::WaitForExit(int* exit_code) { |
return WaitForExitWithTimeout(TimeDelta::Max(), exit_code); |