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