LCOV - app.info - ipc/chromium/src/base/process_util_posix.cc

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-04-21 | 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            4188 : }  // namespace base

Generated by: LCOV version 1.7