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