• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
5 #include "base/process/kill.h"
6 
7 #include <signal.h>
8 #include <sys/types.h>
9 #include <sys/wait.h>
10 #include <unistd.h>
11 
12 #include "base/files/file_util.h"
13 #include "base/files/scoped_file.h"
14 #include "base/logging.h"
15 #include "base/posix/eintr_wrapper.h"
16 #include "base/process/process_iterator.h"
17 #include "base/synchronization/waitable_event.h"
18 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
19 #include "base/threading/platform_thread.h"
20 
21 namespace base {
22 
23 namespace {
24 
WaitpidWithTimeout(ProcessHandle handle,int * status,base::TimeDelta wait)25 bool WaitpidWithTimeout(ProcessHandle handle,
26                         int* status,
27                         base::TimeDelta wait) {
28   // This POSIX version of this function only guarantees that we wait no less
29   // than |wait| for the process to exit.  The child process may
30   // exit sometime before the timeout has ended but we may still block for up
31   // to 256 milliseconds after the fact.
32   //
33   // waitpid() has no direct support on POSIX for specifying a timeout, you can
34   // either ask it to block indefinitely or return immediately (WNOHANG).
35   // When a child process terminates a SIGCHLD signal is sent to the parent.
36   // Catching this signal would involve installing a signal handler which may
37   // affect other parts of the application and would be difficult to debug.
38   //
39   // Our strategy is to call waitpid() once up front to check if the process
40   // has already exited, otherwise to loop for |wait|, sleeping for
41   // at most 256 milliseconds each time using usleep() and then calling
42   // waitpid().  The amount of time we sleep starts out at 1 milliseconds, and
43   // we double it every 4 sleep cycles.
44   //
45   // usleep() is speced to exit if a signal is received for which a handler
46   // has been installed.  This means that when a SIGCHLD is sent, it will exit
47   // depending on behavior external to this function.
48   //
49   // This function is used primarily for unit tests, if we want to use it in
50   // the application itself it would probably be best to examine other routes.
51 
52   if (wait.InMilliseconds() == base::kNoTimeout) {
53     return HANDLE_EINTR(waitpid(handle, status, 0)) > 0;
54   }
55 
56   pid_t ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG));
57   static const int64 kMaxSleepInMicroseconds = 1 << 18;  // ~256 milliseconds.
58   int64 max_sleep_time_usecs = 1 << 10;  // ~1 milliseconds.
59   int64 double_sleep_time = 0;
60 
61   // If the process hasn't exited yet, then sleep and try again.
62   TimeTicks wakeup_time = TimeTicks::Now() + wait;
63   while (ret_pid == 0) {
64     TimeTicks now = TimeTicks::Now();
65     if (now > wakeup_time)
66       break;
67     // Guaranteed to be non-negative!
68     int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds();
69     // Sleep for a bit while we wait for the process to finish.
70     if (sleep_time_usecs > max_sleep_time_usecs)
71       sleep_time_usecs = max_sleep_time_usecs;
72 
73     // usleep() will return 0 and set errno to EINTR on receipt of a signal
74     // such as SIGCHLD.
75     usleep(sleep_time_usecs);
76     ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG));
77 
78     if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) &&
79         (double_sleep_time++ % 4 == 0)) {
80       max_sleep_time_usecs *= 2;
81     }
82   }
83 
84   return ret_pid > 0;
85 }
86 
GetTerminationStatusImpl(ProcessHandle handle,bool can_block,int * exit_code)87 TerminationStatus GetTerminationStatusImpl(ProcessHandle handle,
88                                            bool can_block,
89                                            int* exit_code) {
90   int status = 0;
91   const pid_t result = HANDLE_EINTR(waitpid(handle, &status,
92                                             can_block ? 0 : WNOHANG));
93   if (result == -1) {
94     DPLOG(ERROR) << "waitpid(" << handle << ")";
95     if (exit_code)
96       *exit_code = 0;
97     return TERMINATION_STATUS_NORMAL_TERMINATION;
98   } else if (result == 0) {
99     // the child hasn't exited yet.
100     if (exit_code)
101       *exit_code = 0;
102     return TERMINATION_STATUS_STILL_RUNNING;
103   }
104 
105   if (exit_code)
106     *exit_code = status;
107 
108   if (WIFSIGNALED(status)) {
109     switch (WTERMSIG(status)) {
110       case SIGABRT:
111       case SIGBUS:
112       case SIGFPE:
113       case SIGILL:
114       case SIGSEGV:
115         return TERMINATION_STATUS_PROCESS_CRASHED;
116       case SIGINT:
117       case SIGKILL:
118       case SIGTERM:
119         return TERMINATION_STATUS_PROCESS_WAS_KILLED;
120       default:
121         break;
122     }
123   }
124 
125   if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
126     return TERMINATION_STATUS_ABNORMAL_TERMINATION;
127 
128   return TERMINATION_STATUS_NORMAL_TERMINATION;
129 }
130 
131 }  // namespace
132 
133 // Attempts to kill the process identified by the given process
134 // entry structure.  Ignores specified exit_code; posix can't force that.
135 // Returns true if this is successful, false otherwise.
KillProcess(ProcessHandle process_id,int exit_code,bool wait)136 bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) {
137   DCHECK_GT(process_id, 1) << " tried to kill invalid process_id";
138   if (process_id <= 1)
139     return false;
140   bool result = kill(process_id, SIGTERM) == 0;
141   if (result && wait) {
142     int tries = 60;
143 
144     if (RunningOnValgrind()) {
145       // Wait for some extra time when running under Valgrind since the child
146       // processes may take some time doing leak checking.
147       tries *= 2;
148     }
149 
150     unsigned sleep_ms = 4;
151 
152     // The process may not end immediately due to pending I/O
153     bool exited = false;
154     while (tries-- > 0) {
155       pid_t pid = HANDLE_EINTR(waitpid(process_id, NULL, WNOHANG));
156       if (pid == process_id) {
157         exited = true;
158         break;
159       }
160       if (pid == -1) {
161         if (errno == ECHILD) {
162           // The wait may fail with ECHILD if another process also waited for
163           // the same pid, causing the process state to get cleaned up.
164           exited = true;
165           break;
166         }
167         DPLOG(ERROR) << "Error waiting for process " << process_id;
168       }
169 
170       usleep(sleep_ms * 1000);
171       const unsigned kMaxSleepMs = 1000;
172       if (sleep_ms < kMaxSleepMs)
173         sleep_ms *= 2;
174     }
175 
176     // If we're waiting and the child hasn't died by now, force it
177     // with a SIGKILL.
178     if (!exited)
179       result = kill(process_id, SIGKILL) == 0;
180   }
181 
182   if (!result)
183     DPLOG(ERROR) << "Unable to terminate process " << process_id;
184 
185   return result;
186 }
187 
KillProcessGroup(ProcessHandle process_group_id)188 bool KillProcessGroup(ProcessHandle process_group_id) {
189   bool result = kill(-1 * process_group_id, SIGKILL) == 0;
190   if (!result)
191     DPLOG(ERROR) << "Unable to terminate process group " << process_group_id;
192   return result;
193 }
194 
GetTerminationStatus(ProcessHandle handle,int * exit_code)195 TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
196   return GetTerminationStatusImpl(handle, false /* can_block */, exit_code);
197 }
198 
GetKnownDeadTerminationStatus(ProcessHandle handle,int * exit_code)199 TerminationStatus GetKnownDeadTerminationStatus(ProcessHandle handle,
200                                                 int* exit_code) {
201   bool result = kill(handle, SIGKILL) == 0;
202 
203   if (!result)
204     DPLOG(ERROR) << "Unable to terminate process " << handle;
205 
206   return GetTerminationStatusImpl(handle, true /* can_block */, exit_code);
207 }
208 
WaitForExitCode(ProcessHandle handle,int * exit_code)209 bool WaitForExitCode(ProcessHandle handle, int* exit_code) {
210   int status;
211   if (HANDLE_EINTR(waitpid(handle, &status, 0)) == -1) {
212     NOTREACHED();
213     return false;
214   }
215 
216   if (WIFEXITED(status)) {
217     *exit_code = WEXITSTATUS(status);
218     return true;
219   }
220 
221   // If it didn't exit cleanly, it must have been signaled.
222   DCHECK(WIFSIGNALED(status));
223   return false;
224 }
225 
WaitForExitCodeWithTimeout(ProcessHandle handle,int * exit_code,base::TimeDelta timeout)226 bool WaitForExitCodeWithTimeout(ProcessHandle handle,
227                                 int* exit_code,
228                                 base::TimeDelta timeout) {
229   int status;
230   if (!WaitpidWithTimeout(handle, &status, timeout))
231     return false;
232   if (WIFSIGNALED(status)) {
233     *exit_code = -1;
234     return true;
235   }
236   if (WIFEXITED(status)) {
237     *exit_code = WEXITSTATUS(status);
238     return true;
239   }
240   return false;
241 }
242 
WaitForProcessesToExit(const FilePath::StringType & executable_name,base::TimeDelta wait,const ProcessFilter * filter)243 bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
244                             base::TimeDelta wait,
245                             const ProcessFilter* filter) {
246   bool result = false;
247 
248   // TODO(port): This is inefficient, but works if there are multiple procs.
249   // TODO(port): use waitpid to avoid leaving zombies around
250 
251   base::TimeTicks end_time = base::TimeTicks::Now() + wait;
252   do {
253     NamedProcessIterator iter(executable_name, filter);
254     if (!iter.NextProcessEntry()) {
255       result = true;
256       break;
257     }
258     base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
259   } while ((end_time - base::TimeTicks::Now()) > base::TimeDelta());
260 
261   return result;
262 }
263 
264 #if defined(OS_MACOSX)
265 // Using kqueue on Mac so that we can wait on non-child processes.
266 // We can't use kqueues on child processes because we need to reap
267 // our own children using wait.
WaitForSingleNonChildProcess(ProcessHandle handle,base::TimeDelta wait)268 static bool WaitForSingleNonChildProcess(ProcessHandle handle,
269                                          base::TimeDelta wait) {
270   DCHECK_GT(handle, 0);
271   DCHECK(wait.InMilliseconds() == base::kNoTimeout || wait > base::TimeDelta());
272 
273   ScopedFD kq(kqueue());
274   if (!kq.is_valid()) {
275     DPLOG(ERROR) << "kqueue";
276     return false;
277   }
278 
279   struct kevent change = {0};
280   EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
281   int result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL));
282   if (result == -1) {
283     if (errno == ESRCH) {
284       // If the process wasn't found, it must be dead.
285       return true;
286     }
287 
288     DPLOG(ERROR) << "kevent (setup " << handle << ")";
289     return false;
290   }
291 
292   // Keep track of the elapsed time to be able to restart kevent if it's
293   // interrupted.
294   bool wait_forever = wait.InMilliseconds() == base::kNoTimeout;
295   base::TimeDelta remaining_delta;
296   base::TimeTicks deadline;
297   if (!wait_forever) {
298     remaining_delta = wait;
299     deadline = base::TimeTicks::Now() + remaining_delta;
300   }
301 
302   result = -1;
303   struct kevent event = {0};
304 
305   while (wait_forever || remaining_delta > base::TimeDelta()) {
306     struct timespec remaining_timespec;
307     struct timespec* remaining_timespec_ptr;
308     if (wait_forever) {
309       remaining_timespec_ptr = NULL;
310     } else {
311       remaining_timespec = remaining_delta.ToTimeSpec();
312       remaining_timespec_ptr = &remaining_timespec;
313     }
314 
315     result = kevent(kq.get(), NULL, 0, &event, 1, remaining_timespec_ptr);
316 
317     if (result == -1 && errno == EINTR) {
318       if (!wait_forever) {
319         remaining_delta = deadline - base::TimeTicks::Now();
320       }
321       result = 0;
322     } else {
323       break;
324     }
325   }
326 
327   if (result < 0) {
328     DPLOG(ERROR) << "kevent (wait " << handle << ")";
329     return false;
330   } else if (result > 1) {
331     DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result "
332                 << result;
333     return false;
334   } else if (result == 0) {
335     // Timed out.
336     return false;
337   }
338 
339   DCHECK_EQ(result, 1);
340 
341   if (event.filter != EVFILT_PROC ||
342       (event.fflags & NOTE_EXIT) == 0 ||
343       event.ident != static_cast<uintptr_t>(handle)) {
344     DLOG(ERROR) << "kevent (wait " << handle
345                 << "): unexpected event: filter=" << event.filter
346                 << ", fflags=" << event.fflags
347                 << ", ident=" << event.ident;
348     return false;
349   }
350 
351   return true;
352 }
353 #endif  // OS_MACOSX
354 
WaitForSingleProcess(ProcessHandle handle,base::TimeDelta wait)355 bool WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) {
356   ProcessHandle parent_pid = GetParentProcessId(handle);
357   ProcessHandle our_pid = Process::Current().handle();
358   if (parent_pid != our_pid) {
359 #if defined(OS_MACOSX)
360     // On Mac we can wait on non child processes.
361     return WaitForSingleNonChildProcess(handle, wait);
362 #else
363     // Currently on Linux we can't handle non child processes.
364     NOTIMPLEMENTED();
365 #endif  // OS_MACOSX
366   }
367 
368   int status;
369   if (!WaitpidWithTimeout(handle, &status, wait))
370     return false;
371   return WIFEXITED(status);
372 }
373 
CleanupProcesses(const FilePath::StringType & executable_name,base::TimeDelta wait,int exit_code,const ProcessFilter * filter)374 bool CleanupProcesses(const FilePath::StringType& executable_name,
375                       base::TimeDelta wait,
376                       int exit_code,
377                       const ProcessFilter* filter) {
378   bool exited_cleanly = WaitForProcessesToExit(executable_name, wait, filter);
379   if (!exited_cleanly)
380     KillProcesses(executable_name, exit_code, filter);
381   return exited_cleanly;
382 }
383 
384 #if !defined(OS_MACOSX)
385 
386 namespace {
387 
388 // Return true if the given child is dead. This will also reap the process.
389 // Doesn't block.
IsChildDead(pid_t child)390 static bool IsChildDead(pid_t child) {
391   const pid_t result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG));
392   if (result == -1) {
393     DPLOG(ERROR) << "waitpid(" << child << ")";
394     NOTREACHED();
395   } else if (result > 0) {
396     // The child has died.
397     return true;
398   }
399 
400   return false;
401 }
402 
403 // A thread class which waits for the given child to exit and reaps it.
404 // If the child doesn't exit within a couple of seconds, kill it.
405 class BackgroundReaper : public PlatformThread::Delegate {
406  public:
BackgroundReaper(pid_t child,unsigned timeout)407   BackgroundReaper(pid_t child, unsigned timeout)
408       : child_(child),
409         timeout_(timeout) {
410   }
411 
412   // Overridden from PlatformThread::Delegate:
ThreadMain()413   virtual void ThreadMain() OVERRIDE {
414     WaitForChildToDie();
415     delete this;
416   }
417 
WaitForChildToDie()418   void WaitForChildToDie() {
419     // Wait forever case.
420     if (timeout_ == 0) {
421       pid_t r = HANDLE_EINTR(waitpid(child_, NULL, 0));
422       if (r != child_) {
423         DPLOG(ERROR) << "While waiting for " << child_
424                      << " to terminate, we got the following result: " << r;
425       }
426       return;
427     }
428 
429     // There's no good way to wait for a specific child to exit in a timed
430     // fashion. (No kqueue on Linux), so we just loop and sleep.
431 
432     // Wait for 2 * timeout_ 500 milliseconds intervals.
433     for (unsigned i = 0; i < 2 * timeout_; ++i) {
434       PlatformThread::Sleep(TimeDelta::FromMilliseconds(500));
435       if (IsChildDead(child_))
436         return;
437     }
438 
439     if (kill(child_, SIGKILL) == 0) {
440       // SIGKILL is uncatchable. Since the signal was delivered, we can
441       // just wait for the process to die now in a blocking manner.
442       if (HANDLE_EINTR(waitpid(child_, NULL, 0)) < 0)
443         DPLOG(WARNING) << "waitpid";
444     } else {
445       DLOG(ERROR) << "While waiting for " << child_ << " to terminate we"
446                   << " failed to deliver a SIGKILL signal (" << errno << ").";
447     }
448   }
449 
450  private:
451   const pid_t child_;
452   // Number of seconds to wait, if 0 then wait forever and do not attempt to
453   // kill |child_|.
454   const unsigned timeout_;
455 
456   DISALLOW_COPY_AND_ASSIGN(BackgroundReaper);
457 };
458 
459 }  // namespace
460 
EnsureProcessTerminated(ProcessHandle process)461 void EnsureProcessTerminated(ProcessHandle process) {
462   // If the child is already dead, then there's nothing to do.
463   if (IsChildDead(process))
464     return;
465 
466   const unsigned timeout = 2;  // seconds
467   BackgroundReaper* reaper = new BackgroundReaper(process, timeout);
468   PlatformThread::CreateNonJoinable(0, reaper);
469 }
470 
EnsureProcessGetsReaped(ProcessHandle process)471 void EnsureProcessGetsReaped(ProcessHandle process) {
472   // If the child is already dead, then there's nothing to do.
473   if (IsChildDead(process))
474     return;
475 
476   BackgroundReaper* reaper = new BackgroundReaper(process, 0);
477   PlatformThread::CreateNonJoinable(0, reaper);
478 }
479 
480 #endif  // !defined(OS_MACOSX)
481 
482 }  // namespace base
483