LCOV - code coverage report
Current view: directory - ipc/chromium/src/base - process_util_posix.cc (source / functions) Found Hit Coverage
Test: app.info Lines: 251 6 2.4 %
Date: 2012-06-02 Functions: 30 4 13.3 %

       1                 : //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
       3                 : // Use of this source code is governed by a BSD-style license that can be
       4                 : // found in the LICENSE file.
       5                 : 
       6                 : #include <dirent.h>
       7                 : #include <errno.h>
       8                 : #include <fcntl.h>
       9                 : #include <signal.h>
      10                 : #include <stdlib.h>
      11                 : #include <sys/resource.h>
      12                 : #include <sys/time.h>
      13                 : #include <sys/types.h>
      14                 : #include <sys/wait.h>
      15                 : #include <unistd.h>
      16                 : 
      17                 : #include <limits>
      18                 : #include <set>
      19                 : 
      20                 : #include "base/basictypes.h"
      21                 : #include "base/eintr_wrapper.h"
      22                 : #include "base/logging.h"
      23                 : #include "base/platform_thread.h"
      24                 : #include "base/process_util.h"
      25                 : #include "base/scoped_ptr.h"
      26                 : #include "base/sys_info.h"
      27                 : #include "base/time.h"
      28                 : #include "base/waitable_event.h"
      29                 : #include "base/dir_reader_posix.h"
      30                 : 
      31                 : const int kMicrosecondsPerSecond = 1000000;
      32                 : 
      33                 : namespace base {
      34                 : 
      35               1 : ProcessId GetCurrentProcId() {
      36               1 :   return getpid();
      37                 : }
      38                 : 
      39               0 : ProcessHandle GetCurrentProcessHandle() {
      40               0 :   return GetCurrentProcId();
      41                 : }
      42                 : 
      43               1 : bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
      44                 :   // On Posix platforms, process handles are the same as PIDs, so we
      45                 :   // don't need to do anything.
      46               1 :   *handle = pid;
      47               1 :   return true;
      48                 : }
      49                 : 
      50               0 : bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
      51                 :   // On POSIX permissions are checked for each operation on process,
      52                 :   // not when opening a "handle".
      53               0 :   return OpenProcessHandle(pid, handle);
      54                 : }
      55                 : 
      56               0 : void CloseProcessHandle(ProcessHandle process) {
      57                 :   // See OpenProcessHandle, nothing to do.
      58                 :   return;
      59                 : }
      60                 : 
      61               0 : ProcessId GetProcId(ProcessHandle process) {
      62               0 :   return process;
      63                 : }
      64                 : 
      65                 : // Attempts to kill the process identified by the given process
      66                 : // entry structure.  Ignores specified exit_code; posix can't force that.
      67                 : // Returns true if this is successful, false otherwise.
      68               0 : bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) {
      69               0 :   bool result = kill(process_id, SIGTERM) == 0;
      70                 : 
      71               0 :   if (result && wait) {
      72               0 :     int tries = 60;
      73                 :     // The process may not end immediately due to pending I/O
      74               0 :     while (tries-- > 0) {
      75               0 :       int pid = HANDLE_EINTR(waitpid(process_id, NULL, WNOHANG));
      76               0 :       if (pid == process_id)
      77               0 :         break;
      78                 : 
      79               0 :       sleep(1);
      80                 :     }
      81                 : 
      82               0 :     result = kill(process_id, SIGKILL) == 0;
      83                 :   }
      84                 : 
      85               0 :   if (!result)
      86               0 :     DLOG(ERROR) << "Unable to terminate process.";
      87                 : 
      88               0 :   return result;
      89                 : }
      90                 : 
      91                 : #ifdef ANDROID
      92                 : typedef unsigned long int rlim_t;
      93                 : #endif
      94                 : 
      95                 : // A class to handle auto-closing of DIR*'s.
      96                 : class ScopedDIRClose {
      97                 :  public:
      98               0 :   inline void operator()(DIR* x) const {
      99               0 :     if (x) {
     100               0 :       closedir(x);
     101                 :     }
     102               0 :   }
     103                 : };
     104                 : typedef scoped_ptr_malloc<DIR, ScopedDIRClose> ScopedDIR;
     105                 : 
     106                 : 
     107               0 : void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) {
     108                 :   // DANGER: no calls to malloc are allowed from now on:
     109                 :   // http://crbug.com/36678
     110                 : #if defined(ANDROID)
     111                 :   static const rlim_t kSystemDefaultMaxFds = 1024;
     112                 :   static const char kFDDir[] = "/proc/self/fd";
     113                 : #elif defined(OS_LINUX)
     114                 :   static const rlim_t kSystemDefaultMaxFds = 8192;
     115                 :   static const char kFDDir[] = "/proc/self/fd";
     116                 : #elif defined(OS_MACOSX)
     117                 :   static const rlim_t kSystemDefaultMaxFds = 256;
     118                 :   static const char kFDDir[] = "/dev/fd";
     119                 : #endif
     120                 : 
     121                 :   // Get the maximum number of FDs possible.
     122                 :   struct rlimit nofile;
     123                 :   rlim_t max_fds;
     124               0 :   if (getrlimit(RLIMIT_NOFILE, &nofile)) {
     125                 :     // getrlimit failed. Take a best guess.
     126               0 :     max_fds = kSystemDefaultMaxFds;
     127               0 :     DLOG(ERROR) << "getrlimit(RLIMIT_NOFILE) failed: " << errno;
     128                 :   } else {
     129               0 :     max_fds = nofile.rlim_cur;
     130                 :   }
     131                 : 
     132               0 :   if (max_fds > INT_MAX)
     133               0 :     max_fds = INT_MAX;
     134                 : 
     135               0 :   DirReaderPosix fd_dir(kFDDir);
     136                 : 
     137               0 :   if (!fd_dir.IsValid()) {
     138                 :     // Fallback case: Try every possible fd.
     139               0 :     for (rlim_t i = 0; i < max_fds; ++i) {
     140               0 :       const int fd = static_cast<int>(i);
     141               0 :       if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
     142               0 :         continue;
     143               0 :       InjectiveMultimap::const_iterator j;
     144               0 :       for (j = saved_mapping.begin(); j != saved_mapping.end(); j++) {
     145               0 :         if (fd == j->dest)
     146               0 :           break;
     147                 :       }
     148               0 :       if (j != saved_mapping.end())
     149               0 :         continue;
     150                 : 
     151                 :       // Since we're just trying to close anything we can find,
     152                 :       // ignore any error return values of close().
     153               0 :       HANDLE_EINTR(close(fd));
     154                 :     }
     155                 :     return;
     156                 :   }
     157                 : 
     158               0 :   const int dir_fd = fd_dir.fd();
     159                 : 
     160               0 :   for ( ; fd_dir.Next(); ) {
     161                 :     // Skip . and .. entries.
     162               0 :     if (fd_dir.name()[0] == '.')
     163               0 :       continue;
     164                 : 
     165                 :     char *endptr;
     166               0 :     errno = 0;
     167               0 :     const long int fd = strtol(fd_dir.name(), &endptr, 10);
     168               0 :     if (fd_dir.name()[0] == 0 || *endptr || fd < 0 || errno)
     169               0 :       continue;
     170               0 :     if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
     171               0 :       continue;
     172               0 :     InjectiveMultimap::const_iterator i;
     173               0 :     for (i = saved_mapping.begin(); i != saved_mapping.end(); i++) {
     174               0 :       if (fd == i->dest)
     175               0 :         break;
     176                 :     }
     177               0 :     if (i != saved_mapping.end())
     178               0 :       continue;
     179               0 :     if (fd == dir_fd)
     180               0 :       continue;
     181                 : 
     182                 :     // When running under Valgrind, Valgrind opens several FDs for its
     183                 :     // own use and will complain if we try to close them.  All of
     184                 :     // these FDs are >= |max_fds|, so we can check against that here
     185                 :     // before closing.  See https://bugs.kde.org/show_bug.cgi?id=191758
     186               0 :     if (fd < static_cast<int>(max_fds)) {
     187               0 :       int ret = HANDLE_EINTR(close(fd));
     188               0 :       if (ret != 0) {
     189               0 :         DLOG(ERROR) << "Problem closing fd";
     190                 :       }
     191                 :     }
     192                 :   }
     193                 : }
     194                 : 
     195                 : // Sets all file descriptors to close on exec except for stdin, stdout
     196                 : // and stderr.
     197                 : // TODO(agl): Remove this function. It's fundamentally broken for multithreaded
     198                 : // apps.
     199               0 : void SetAllFDsToCloseOnExec() {
     200                 : #if defined(OS_LINUX)
     201               0 :   const char fd_dir[] = "/proc/self/fd";
     202                 : #elif defined(OS_MACOSX)
     203                 :   const char fd_dir[] = "/dev/fd";
     204                 : #endif
     205               0 :   ScopedDIR dir_closer(opendir(fd_dir));
     206               0 :   DIR *dir = dir_closer.get();
     207               0 :   if (NULL == dir) {
     208               0 :     DLOG(ERROR) << "Unable to open " << fd_dir;
     209                 :     return;
     210                 :   }
     211                 : 
     212                 :   struct dirent *ent;
     213               0 :   while ((ent = readdir(dir))) {
     214                 :     // Skip . and .. entries.
     215               0 :     if (ent->d_name[0] == '.')
     216               0 :       continue;
     217               0 :     int i = atoi(ent->d_name);
     218                 :     // We don't close stdin, stdout or stderr.
     219               0 :     if (i <= STDERR_FILENO)
     220               0 :       continue;
     221                 : 
     222               0 :     int flags = fcntl(i, F_GETFD);
     223               0 :     if ((flags == -1) || (fcntl(i, F_SETFD, flags | FD_CLOEXEC) == -1)) {
     224               0 :       DLOG(ERROR) << "fcntl failure.";
     225                 :     }
     226                 :   }
     227                 : }
     228                 : 
     229               0 : ProcessMetrics::ProcessMetrics(ProcessHandle process) : process_(process),
     230                 :                                                         last_time_(0),
     231               0 :                                                         last_system_time_(0) {
     232               0 :   processor_count_ = base::SysInfo::NumberOfProcessors();
     233               0 : }
     234                 : 
     235                 : // static
     236               0 : ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
     237               0 :   return new ProcessMetrics(process);
     238                 : }
     239                 : 
     240               0 : ProcessMetrics::~ProcessMetrics() { }
     241                 : 
     242               0 : void EnableTerminationOnHeapCorruption() {
     243                 :   // On POSIX, there nothing to do AFAIK.
     244               0 : }
     245                 : 
     246               0 : void RaiseProcessToHighPriority() {
     247                 :   // On POSIX, we don't actually do anything here.  We could try to nice() or
     248                 :   // setpriority() or sched_getscheduler, but these all require extra rights.
     249               0 : }
     250                 : 
     251               0 : bool DidProcessCrash(bool* child_exited, ProcessHandle handle) {
     252                 :   int status;
     253               0 :   const int result = HANDLE_EINTR(waitpid(handle, &status, WNOHANG));
     254               0 :   if (result == -1) {
     255               0 :     LOG(ERROR) << "waitpid failed pid:" << handle << " errno:" << errno;
     256               0 :     if (child_exited)
     257               0 :       *child_exited = false;
     258               0 :     return false;
     259               0 :   } else if (result == 0) {
     260                 :     // the child hasn't exited yet.
     261               0 :     if (child_exited)
     262               0 :       *child_exited = false;
     263               0 :     return false;
     264                 :   }
     265                 : 
     266               0 :   if (child_exited)
     267               0 :     *child_exited = true;
     268                 : 
     269               0 :   if (WIFSIGNALED(status)) {
     270               0 :     switch(WTERMSIG(status)) {
     271                 :       case SIGSEGV:
     272                 :       case SIGILL:
     273                 :       case SIGABRT:
     274                 :       case SIGFPE:
     275               0 :         return true;
     276                 :       default:
     277               0 :         return false;
     278                 :     }
     279                 :   }
     280                 : 
     281               0 :   if (WIFEXITED(status))
     282               0 :     return WEXITSTATUS(status) != 0;
     283                 : 
     284               0 :   return false;
     285                 : }
     286                 : 
     287               0 : bool WaitForExitCode(ProcessHandle handle, int* exit_code) {
     288                 :   int status;
     289               0 :   if (HANDLE_EINTR(waitpid(handle, &status, 0)) == -1) {
     290               0 :     NOTREACHED();
     291               0 :     return false;
     292                 :   }
     293                 : 
     294               0 :   if (WIFEXITED(status)) {
     295               0 :     *exit_code = WEXITSTATUS(status);
     296               0 :     return true;
     297                 :   }
     298                 : 
     299                 :   // If it didn't exit cleanly, it must have been signaled.
     300               0 :   DCHECK(WIFSIGNALED(status));
     301               0 :   return false;
     302                 : }
     303                 : 
     304                 : namespace {
     305                 : 
     306               0 : int WaitpidWithTimeout(ProcessHandle handle, int wait_milliseconds,
     307                 :                        bool* success) {
     308                 :   // This POSIX version of this function only guarantees that we wait no less
     309                 :   // than |wait_milliseconds| for the proces to exit.  The child process may
     310                 :   // exit sometime before the timeout has ended but we may still block for
     311                 :   // up to 0.25 seconds after the fact.
     312                 :   //
     313                 :   // waitpid() has no direct support on POSIX for specifying a timeout, you can
     314                 :   // either ask it to block indefinitely or return immediately (WNOHANG).
     315                 :   // When a child process terminates a SIGCHLD signal is sent to the parent.
     316                 :   // Catching this signal would involve installing a signal handler which may
     317                 :   // affect other parts of the application and would be difficult to debug.
     318                 :   //
     319                 :   // Our strategy is to call waitpid() once up front to check if the process
     320                 :   // has already exited, otherwise to loop for wait_milliseconds, sleeping for
     321                 :   // at most 0.25 secs each time using usleep() and then calling waitpid().
     322                 :   //
     323                 :   // usleep() is speced to exit if a signal is received for which a handler
     324                 :   // has been installed.  This means that when a SIGCHLD is sent, it will exit
     325                 :   // depending on behavior external to this function.
     326                 :   //
     327                 :   // This function is used primarily for unit tests, if we want to use it in
     328                 :   // the application itself it would probably be best to examine other routes.
     329               0 :   int status = -1;
     330               0 :   pid_t ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG));
     331                 :   static const int64 kQuarterSecondInMicroseconds = kMicrosecondsPerSecond/4;
     332                 : 
     333                 :   // If the process hasn't exited yet, then sleep and try again.
     334                 :   Time wakeup_time = Time::Now() + TimeDelta::FromMilliseconds(
     335               0 :       wait_milliseconds);
     336               0 :   while (ret_pid == 0) {
     337               0 :     Time now = Time::Now();
     338               0 :     if (now > wakeup_time)
     339               0 :       break;
     340                 :     // Guaranteed to be non-negative!
     341               0 :     int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds();
     342                 :     // Don't sleep for more than 0.25 secs at a time.
     343               0 :     if (sleep_time_usecs > kQuarterSecondInMicroseconds) {
     344               0 :       sleep_time_usecs = kQuarterSecondInMicroseconds;
     345                 :     }
     346                 : 
     347                 :     // usleep() will return 0 and set errno to EINTR on receipt of a signal
     348                 :     // such as SIGCHLD.
     349               0 :     usleep(sleep_time_usecs);
     350               0 :     ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG));
     351                 :   }
     352                 : 
     353               0 :   if (success)
     354               0 :     *success = (ret_pid != -1);
     355                 : 
     356               0 :   return status;
     357                 : }
     358                 : 
     359                 : }  // namespace
     360                 : 
     361               0 : bool WaitForSingleProcess(ProcessHandle handle, int wait_milliseconds) {
     362                 :   bool waitpid_success;
     363                 :   int status;
     364               0 :   if (wait_milliseconds == base::kNoTimeout)
     365               0 :     waitpid_success = (HANDLE_EINTR(waitpid(handle, &status, 0)) != -1);
     366                 :   else
     367               0 :     status = WaitpidWithTimeout(handle, wait_milliseconds, &waitpid_success);
     368               0 :   if (status != -1) {
     369               0 :     DCHECK(waitpid_success);
     370               0 :     return WIFEXITED(status);
     371                 :   } else {
     372               0 :     return false;
     373                 :   }
     374                 : }
     375                 : 
     376               0 : bool CrashAwareSleep(ProcessHandle handle, int wait_milliseconds) {
     377                 :   bool waitpid_success;
     378               0 :   int status = WaitpidWithTimeout(handle, wait_milliseconds, &waitpid_success);
     379               0 :   if (status != -1) {
     380               0 :     DCHECK(waitpid_success);
     381               0 :     return !(WIFEXITED(status) || WIFSIGNALED(status));
     382                 :   } else {
     383                 :     // If waitpid returned with an error, then the process doesn't exist
     384                 :     // (which most probably means it didn't exist before our call).
     385               0 :     return waitpid_success;
     386                 :   }
     387                 : }
     388                 : 
     389                 : namespace {
     390                 : 
     391               0 : int64 TimeValToMicroseconds(const struct timeval& tv) {
     392               0 :   return tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec;
     393                 : }
     394                 : 
     395                 : }
     396                 : 
     397               0 : int ProcessMetrics::GetCPUUsage() {
     398                 :   struct timeval now;
     399                 :   struct rusage usage;
     400                 : 
     401               0 :   int retval = gettimeofday(&now, NULL);
     402               0 :   if (retval)
     403               0 :     return 0;
     404               0 :   retval = getrusage(RUSAGE_SELF, &usage);
     405               0 :   if (retval)
     406               0 :     return 0;
     407                 : 
     408               0 :   int64 system_time = (TimeValToMicroseconds(usage.ru_stime) +
     409               0 :                        TimeValToMicroseconds(usage.ru_utime)) /
     410               0 :                         processor_count_;
     411               0 :   int64 time = TimeValToMicroseconds(now);
     412                 : 
     413               0 :   if ((last_system_time_ == 0) || (last_time_ == 0)) {
     414                 :     // First call, just set the last values.
     415               0 :     last_system_time_ = system_time;
     416               0 :     last_time_ = time;
     417               0 :     return 0;
     418                 :   }
     419                 : 
     420               0 :   int64 system_time_delta = system_time - last_system_time_;
     421               0 :   int64 time_delta = time - last_time_;
     422               0 :   DCHECK(time_delta != 0);
     423               0 :   if (time_delta == 0)
     424               0 :     return 0;
     425                 : 
     426                 :   // We add time_delta / 2 so the result is rounded.
     427                 :   int cpu = static_cast<int>((system_time_delta * 100 + time_delta / 2) /
     428               0 :                              time_delta);
     429                 : 
     430               0 :   last_system_time_ = system_time;
     431               0 :   last_time_ = time;
     432                 : 
     433               0 :   return cpu;
     434                 : }
     435                 : 
     436               0 : bool GetAppOutput(const CommandLine& cl, std::string* output) {
     437                 :   int pipe_fd[2];
     438                 :   pid_t pid;
     439                 : 
     440                 :   // Illegal to allocate memory after fork and before execvp
     441               0 :   InjectiveMultimap fd_shuffle1, fd_shuffle2;
     442               0 :   fd_shuffle1.reserve(3);
     443               0 :   fd_shuffle2.reserve(3);
     444               0 :   const std::vector<std::string>& argv = cl.argv();
     445               0 :   scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
     446                 : 
     447               0 :   if (pipe(pipe_fd) < 0)
     448               0 :     return false;
     449                 : 
     450               0 :   switch (pid = fork()) {
     451                 :     case -1:  // error
     452               0 :       close(pipe_fd[0]);
     453               0 :       close(pipe_fd[1]);
     454               0 :       return false;
     455                 :     case 0:  // child
     456                 :       {
     457                 :         // Obscure fork() rule: in the child, if you don't end up doing exec*(),
     458                 :         // you call _exit() instead of exit(). This is because _exit() does not
     459                 :         // call any previously-registered (in the parent) exit handlers, which
     460                 :         // might do things like block waiting for threads that don't even exist
     461                 :         // in the child.
     462               0 :         int dev_null = open("/dev/null", O_WRONLY);
     463               0 :         if (dev_null < 0)
     464               0 :           _exit(127);
     465                 : 
     466               0 :         fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true));
     467               0 :         fd_shuffle1.push_back(InjectionArc(dev_null, STDERR_FILENO, true));
     468               0 :         fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true));
     469                 :         // Adding another element here? Remeber to increase the argument to
     470                 :         // reserve(), above.
     471                 : 
     472                 :         std::copy(fd_shuffle1.begin(), fd_shuffle1.end(),
     473               0 :                   std::back_inserter(fd_shuffle2));
     474                 : 
     475                 :         // fd_shuffle1 is mutated by this call because it cannot malloc.
     476               0 :         if (!ShuffleFileDescriptors(&fd_shuffle1))
     477               0 :           _exit(127);
     478                 : 
     479               0 :         CloseSuperfluousFds(fd_shuffle2);
     480                 : 
     481               0 :         for (size_t i = 0; i < argv.size(); i++)
     482               0 :           argv_cstr[i] = const_cast<char*>(argv[i].c_str());
     483               0 :         argv_cstr[argv.size()] = NULL;
     484               0 :         execvp(argv_cstr[0], argv_cstr.get());
     485               0 :         _exit(127);
     486                 :       }
     487                 :     default:  // parent
     488                 :       {
     489                 :         // Close our writing end of pipe now. Otherwise later read would not
     490                 :         // be able to detect end of child's output (in theory we could still
     491                 :         // write to the pipe).
     492               0 :         close(pipe_fd[1]);
     493                 : 
     494               0 :         int exit_code = EXIT_FAILURE;
     495               0 :         bool success = WaitForExitCode(pid, &exit_code);
     496               0 :         if (!success || exit_code != EXIT_SUCCESS) {
     497               0 :           close(pipe_fd[0]);
     498               0 :           return false;
     499                 :         }
     500                 : 
     501                 :         char buffer[256];
     502               0 :         std::string buf_output;
     503                 : 
     504               0 :         while (true) {
     505                 :           ssize_t bytes_read =
     506               0 :               HANDLE_EINTR(read(pipe_fd[0], buffer, sizeof(buffer)));
     507               0 :           if (bytes_read <= 0)
     508                 :             break;
     509               0 :           buf_output.append(buffer, bytes_read);
     510                 :         }
     511               0 :         output->swap(buf_output);
     512               0 :         close(pipe_fd[0]);
     513               0 :         return true;
     514                 :       }
     515                 :   }
     516                 : }
     517                 : 
     518               0 : int GetProcessCount(const std::wstring& executable_name,
     519                 :                     const ProcessFilter* filter) {
     520               0 :   int count = 0;
     521                 : 
     522               0 :   NamedProcessIterator iter(executable_name, filter);
     523               0 :   while (iter.NextProcessEntry())
     524               0 :     ++count;
     525               0 :   return count;
     526                 : }
     527                 : 
     528               0 : bool KillProcesses(const std::wstring& executable_name, int exit_code,
     529                 :                    const ProcessFilter* filter) {
     530               0 :   bool result = true;
     531                 :   const ProcessEntry* entry;
     532                 : 
     533               0 :   NamedProcessIterator iter(executable_name, filter);
     534               0 :   while ((entry = iter.NextProcessEntry()) != NULL)
     535               0 :     result = KillProcess((*entry).pid, exit_code, true) && result;
     536                 : 
     537               0 :   return result;
     538                 : }
     539                 : 
     540               0 : bool WaitForProcessesToExit(const std::wstring& executable_name,
     541                 :                             int wait_milliseconds,
     542                 :                             const ProcessFilter* filter) {
     543               0 :   bool result = false;
     544                 : 
     545                 :   // TODO(port): This is inefficient, but works if there are multiple procs.
     546                 :   // TODO(port): use waitpid to avoid leaving zombies around
     547                 : 
     548                 :   base::Time end_time = base::Time::Now() +
     549               0 :       base::TimeDelta::FromMilliseconds(wait_milliseconds);
     550               0 :   do {
     551               0 :     NamedProcessIterator iter(executable_name, filter);
     552               0 :     if (!iter.NextProcessEntry()) {
     553               0 :       result = true;
     554                 :       break;
     555                 :     }
     556               0 :     PlatformThread::Sleep(100);
     557               0 :   } while ((base::Time::Now() - end_time) > base::TimeDelta());
     558                 : 
     559               0 :   return result;
     560                 : }
     561                 : 
     562               0 : bool CleanupProcesses(const std::wstring& executable_name,
     563                 :                       int wait_milliseconds,
     564                 :                       int exit_code,
     565                 :                       const ProcessFilter* filter) {
     566                 :   bool exited_cleanly =
     567                 :       WaitForProcessesToExit(executable_name, wait_milliseconds,
     568               0 :                            filter);
     569               0 :   if (!exited_cleanly)
     570               0 :     KillProcesses(executable_name, exit_code, filter);
     571               0 :   return exited_cleanly;
     572                 : }
     573                 : 
     574            4392 : }  // namespace base

Generated by: LCOV version 1.7