kill_posix.cc 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. // Copyright (c) 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/process/kill.h"
  5. #include <errno.h>
  6. #include <signal.h>
  7. #include <sys/types.h>
  8. #include <sys/wait.h>
  9. #include <unistd.h>
  10. #include "base/debug/activity_tracker.h"
  11. #include "base/files/file_util.h"
  12. #include "base/logging.h"
  13. #include "base/posix/eintr_wrapper.h"
  14. #include "base/process/process_iterator.h"
  15. #include "base/threading/platform_thread.h"
  16. #include "build/build_config.h"
  17. namespace base {
  18. namespace {
  19. TerminationStatus GetTerminationStatusImpl(ProcessHandle handle,
  20. bool can_block,
  21. int* exit_code) {
  22. DCHECK(exit_code);
  23. int status = 0;
  24. const pid_t result = HANDLE_EINTR(waitpid(handle, &status,
  25. can_block ? 0 : WNOHANG));
  26. if (result == -1) {
  27. DPLOG(ERROR) << "waitpid(" << handle << ")";
  28. *exit_code = 0;
  29. return TERMINATION_STATUS_NORMAL_TERMINATION;
  30. }
  31. if (result == 0) {
  32. // the child hasn't exited yet.
  33. *exit_code = 0;
  34. return TERMINATION_STATUS_STILL_RUNNING;
  35. }
  36. *exit_code = status;
  37. if (WIFSIGNALED(status)) {
  38. switch (WTERMSIG(status)) {
  39. case SIGABRT:
  40. case SIGBUS:
  41. case SIGFPE:
  42. case SIGILL:
  43. case SIGSEGV:
  44. case SIGTRAP:
  45. case SIGSYS:
  46. return TERMINATION_STATUS_PROCESS_CRASHED;
  47. case SIGKILL:
  48. #if BUILDFLAG(IS_CHROMEOS)
  49. // On ChromeOS, only way a process gets kill by SIGKILL
  50. // is by oom-killer.
  51. return TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM;
  52. #endif
  53. case SIGINT:
  54. case SIGTERM:
  55. return TERMINATION_STATUS_PROCESS_WAS_KILLED;
  56. default:
  57. break;
  58. }
  59. }
  60. if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
  61. return TERMINATION_STATUS_ABNORMAL_TERMINATION;
  62. return TERMINATION_STATUS_NORMAL_TERMINATION;
  63. }
  64. } // namespace
  65. TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
  66. return GetTerminationStatusImpl(handle, false /* can_block */, exit_code);
  67. }
  68. TerminationStatus GetKnownDeadTerminationStatus(ProcessHandle handle,
  69. int* exit_code) {
  70. bool result = kill(handle, SIGKILL) == 0;
  71. if (!result)
  72. DPLOG(ERROR) << "Unable to terminate process " << handle;
  73. return GetTerminationStatusImpl(handle, true /* can_block */, exit_code);
  74. }
  75. bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
  76. TimeDelta wait,
  77. const ProcessFilter* filter) {
  78. bool result = false;
  79. // TODO(port): This is inefficient, but works if there are multiple procs.
  80. // TODO(port): use waitpid to avoid leaving zombies around
  81. TimeTicks end_time = TimeTicks::Now() + wait;
  82. do {
  83. NamedProcessIterator iter(executable_name, filter);
  84. if (!iter.NextProcessEntry()) {
  85. result = true;
  86. break;
  87. }
  88. PlatformThread::Sleep(Milliseconds(100));
  89. } while ((end_time - TimeTicks::Now()).is_positive());
  90. return result;
  91. }
  92. bool CleanupProcesses(const FilePath::StringType& executable_name,
  93. TimeDelta wait,
  94. int exit_code,
  95. const ProcessFilter* filter) {
  96. bool exited_cleanly = WaitForProcessesToExit(executable_name, wait, filter);
  97. if (!exited_cleanly)
  98. KillProcesses(executable_name, exit_code, filter);
  99. return exited_cleanly;
  100. }
  101. #if !BUILDFLAG(IS_APPLE)
  102. namespace {
  103. class BackgroundReaper : public PlatformThread::Delegate {
  104. public:
  105. BackgroundReaper(base::Process child_process, const TimeDelta& wait_time)
  106. : child_process_(std::move(child_process)), wait_time_(wait_time) {}
  107. BackgroundReaper(const BackgroundReaper&) = delete;
  108. BackgroundReaper& operator=(const BackgroundReaper&) = delete;
  109. void ThreadMain() override {
  110. if (!wait_time_.is_zero()) {
  111. child_process_.WaitForExitWithTimeout(wait_time_, nullptr);
  112. kill(child_process_.Handle(), SIGKILL);
  113. }
  114. child_process_.WaitForExit(nullptr);
  115. delete this;
  116. }
  117. private:
  118. Process child_process_;
  119. const TimeDelta wait_time_;
  120. };
  121. } // namespace
  122. void EnsureProcessTerminated(Process process) {
  123. DCHECK(!process.is_current());
  124. if (process.WaitForExitWithTimeout(TimeDelta(), nullptr))
  125. return;
  126. PlatformThread::CreateNonJoinable(
  127. 0, new BackgroundReaper(std::move(process), Seconds(2)));
  128. }
  129. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  130. void EnsureProcessGetsReaped(Process process) {
  131. DCHECK(!process.is_current());
  132. // If the child is already dead, then there's nothing to do.
  133. if (process.WaitForExitWithTimeout(TimeDelta(), nullptr))
  134. return;
  135. PlatformThread::CreateNonJoinable(
  136. 0, new BackgroundReaper(std::move(process), TimeDelta()));
  137. }
  138. #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  139. #endif // !BUILDFLAG(IS_APPLE)
  140. } // namespace base