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