diff options
-rw-r--r-- | base/process/kill.h | 23 | ||||
-rw-r--r-- | base/process/kill_posix.cc | 9 | ||||
-rw-r--r-- | chrome/nacl/nacl_helper_linux.cc | 13 | ||||
-rw-r--r-- | content/browser/child_process_launcher.cc | 5 | ||||
-rw-r--r-- | content/zygote/zygote_linux.cc | 11 |
5 files changed, 33 insertions, 28 deletions
diff --git a/base/process/kill.h b/base/process/kill.h index f81ea90..c828c71 100644 --- a/base/process/kill.h +++ b/base/process/kill.h @@ -67,12 +67,23 @@ BASE_EXPORT TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code); #if defined(OS_POSIX) -// Wait for the process to exit and get the termination status. See -// GetTerminationStatus for more information. On POSIX systems, we can't call -// WaitForExitCode and then GetTerminationStatus as the child will be reaped -// when WaitForExitCode return and this information will be lost. -BASE_EXPORT TerminationStatus WaitForTerminationStatus(ProcessHandle handle, - int* exit_code); +// Send a kill signal to the process and then wait for the process to exit +// and get the termination status. +// +// This is used in situations where it is believed that the process is dead +// or dying (because communication with the child process has been cut). +// In order to avoid erroneously returning that the process is still running +// because the kernel is still cleaning it up, this will wait for the process +// to terminate. In order to avoid the risk of hanging while waiting for the +// process to terminate, send a SIGKILL to the process before waiting for the +// termination status. +// +// Note that it is not an option to call WaitForExitCode and then +// GetTerminationStatus as the child will be reaped when WaitForExitCode +// returns, and this information will be lost. +// +BASE_EXPORT TerminationStatus GetKnownDeadTerminationStatus( + ProcessHandle handle, int* exit_code); #endif // defined(OS_POSIX) // Waits for process to exit. On POSIX systems, if the process hasn't been diff --git a/base/process/kill_posix.cc b/base/process/kill_posix.cc index 5938fa5..99d70d9 100644 --- a/base/process/kill_posix.cc +++ b/base/process/kill_posix.cc @@ -195,8 +195,13 @@ TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) { return GetTerminationStatusImpl(handle, false /* can_block */, exit_code); } -TerminationStatus WaitForTerminationStatus(ProcessHandle handle, - int* exit_code) { +TerminationStatus GetKnownDeadTerminationStatus(ProcessHandle handle, + int* exit_code) { + bool result = kill(handle, SIGKILL) == 0; + + if (!result) + DPLOG(ERROR) << "Unable to terminate process " << handle; + return GetTerminationStatusImpl(handle, true /* can_block */, exit_code); } diff --git a/chrome/nacl/nacl_helper_linux.cc b/chrome/nacl/nacl_helper_linux.cc index e823b53..53d247d 100644 --- a/chrome/nacl/nacl_helper_linux.cc +++ b/chrome/nacl/nacl_helper_linux.cc @@ -164,17 +164,10 @@ bool HandleGetTerminationStatusRequest(PickleIterator* input_iter, int exit_code; base::TerminationStatus status; - // See the comment in the Zygote about known_dead. - if (known_dead) { - // Make sure to not perform a blocking wait on something that - // could still be alive. - if (kill(child_to_wait, SIGKILL)) { - PLOG(ERROR) << "kill (" << child_to_wait << ")"; - } - status = base::WaitForTerminationStatus(child_to_wait, &exit_code); - } else { + if (known_dead) + status = base::GetKnownDeadTerminationStatus(child_to_wait, &exit_code); + else status = base::GetTerminationStatus(child_to_wait, &exit_code); - } output_pickle->WriteInt(static_cast<int>(status)); output_pickle->WriteInt(exit_code); return true; diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc index ff17607..721cd5a 100644 --- a/content/browser/child_process_launcher.cc +++ b/content/browser/child_process_launcher.cc @@ -465,6 +465,11 @@ base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus( context_->termination_status_ = ZygoteHostImpl::GetInstance()-> GetTerminationStatus(handle, known_dead, &context_->exit_code_); } else +#elif defined(OS_MACOSX) + if (known_dead) { + context_->termination_status_ = + base::GetKnownDeadTerminationStatus(handle, &context_->exit_code_); + } else #endif { context_->termination_status_ = diff --git a/content/zygote/zygote_linux.cc b/content/zygote/zygote_linux.cc index 4146f92..08f1ecb 100644 --- a/content/zygote/zygote_linux.cc +++ b/content/zygote/zygote_linux.cc @@ -223,16 +223,7 @@ bool Zygote::GetTerminationStatus(base::ProcessHandle real_pid, } else { // Handle the request directly. if (known_dead) { - // If we know that the process is already dead and the kernel is cleaning - // it up, we do want to wait until it becomes a zombie and not risk - // returning eroneously that it is still running. However, we do not - // want to risk a bug where we're told a process is dead when it's not. - // By sending SIGKILL, we make sure that WaitForTerminationStatus will - // return quickly even in this case. - if (kill(child, SIGKILL)) { - PLOG(ERROR) << "kill (" << child << ")"; - } - *status = base::WaitForTerminationStatus(child, exit_code); + *status = base::GetKnownDeadTerminationStatus(child, exit_code); } else { // We don't know if the process is dying, so get its status but don't // wait. |