ipc/chromium/src/base/process_util_posix.cc

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/ipc/chromium/src/base/process_util_posix.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,341 @@
     1.4 +//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
     1.6 +// Use of this source code is governed by a BSD-style license that can be
     1.7 +// found in the LICENSE file.
     1.8 +
     1.9 +#include <dirent.h>
    1.10 +#include <errno.h>
    1.11 +#include <fcntl.h>
    1.12 +#include <signal.h>
    1.13 +#include <stdlib.h>
    1.14 +#include <sys/resource.h>
    1.15 +#include <sys/time.h>
    1.16 +#include <sys/types.h>
    1.17 +#include <sys/wait.h>
    1.18 +#include <unistd.h>
    1.19 +
    1.20 +#include <limits>
    1.21 +#include <set>
    1.22 +
    1.23 +#include "base/basictypes.h"
    1.24 +#include "base/eintr_wrapper.h"
    1.25 +#include "base/logging.h"
    1.26 +#include "base/platform_thread.h"
    1.27 +#include "base/process_util.h"
    1.28 +#include "base/scoped_ptr.h"
    1.29 +#include "base/sys_info.h"
    1.30 +#include "base/time.h"
    1.31 +#include "base/waitable_event.h"
    1.32 +#include "base/dir_reader_posix.h"
    1.33 +
    1.34 +const int kMicrosecondsPerSecond = 1000000;
    1.35 +
    1.36 +namespace base {
    1.37 +
    1.38 +ProcessId GetCurrentProcId() {
    1.39 +  return getpid();
    1.40 +}
    1.41 +
    1.42 +ProcessHandle GetCurrentProcessHandle() {
    1.43 +  return GetCurrentProcId();
    1.44 +}
    1.45 +
    1.46 +bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
    1.47 +  // On Posix platforms, process handles are the same as PIDs, so we
    1.48 +  // don't need to do anything.
    1.49 +  *handle = pid;
    1.50 +  return true;
    1.51 +}
    1.52 +
    1.53 +bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
    1.54 +  // On POSIX permissions are checked for each operation on process,
    1.55 +  // not when opening a "handle".
    1.56 +  return OpenProcessHandle(pid, handle);
    1.57 +}
    1.58 +
    1.59 +void CloseProcessHandle(ProcessHandle process) {
    1.60 +  // See OpenProcessHandle, nothing to do.
    1.61 +  return;
    1.62 +}
    1.63 +
    1.64 +ProcessId GetProcId(ProcessHandle process) {
    1.65 +  return process;
    1.66 +}
    1.67 +
    1.68 +// Attempts to kill the process identified by the given process
    1.69 +// entry structure.  Ignores specified exit_code; posix can't force that.
    1.70 +// Returns true if this is successful, false otherwise.
    1.71 +bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) {
    1.72 +  bool result = kill(process_id, SIGTERM) == 0;
    1.73 +
    1.74 +  if (result && wait) {
    1.75 +    int tries = 60;
    1.76 +    // The process may not end immediately due to pending I/O
    1.77 +    while (tries-- > 0) {
    1.78 +      int pid = HANDLE_EINTR(waitpid(process_id, NULL, WNOHANG));
    1.79 +      if (pid == process_id)
    1.80 +        break;
    1.81 +
    1.82 +      sleep(1);
    1.83 +    }
    1.84 +
    1.85 +    result = kill(process_id, SIGKILL) == 0;
    1.86 +  }
    1.87 +
    1.88 +  if (!result)
    1.89 +    DLOG(ERROR) << "Unable to terminate process.";
    1.90 +
    1.91 +  return result;
    1.92 +}
    1.93 +
    1.94 +#ifdef ANDROID
    1.95 +typedef unsigned long int rlim_t;
    1.96 +#endif
    1.97 +
    1.98 +// A class to handle auto-closing of DIR*'s.
    1.99 +class ScopedDIRClose {
   1.100 + public:
   1.101 +  inline void operator()(DIR* x) const {
   1.102 +    if (x) {
   1.103 +      closedir(x);
   1.104 +    }
   1.105 +  }
   1.106 +};
   1.107 +typedef scoped_ptr_malloc<DIR, ScopedDIRClose> ScopedDIR;
   1.108 +
   1.109 +
   1.110 +void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) {
   1.111 +  // DANGER: no calls to malloc are allowed from now on:
   1.112 +  // http://crbug.com/36678
   1.113 +#if defined(ANDROID)
   1.114 +  static const rlim_t kSystemDefaultMaxFds = 1024;
   1.115 +  static const char kFDDir[] = "/proc/self/fd";
   1.116 +#elif defined(OS_LINUX)
   1.117 +  static const rlim_t kSystemDefaultMaxFds = 8192;
   1.118 +  static const char kFDDir[] = "/proc/self/fd";
   1.119 +#elif defined(OS_MACOSX)
   1.120 +  static const rlim_t kSystemDefaultMaxFds = 256;
   1.121 +  static const char kFDDir[] = "/dev/fd";
   1.122 +#elif defined(OS_BSD)
   1.123 +  // the getrlimit below should never fail, so whatever ..
   1.124 +  static const rlim_t kSystemDefaultMaxFds = 1024;
   1.125 +  // at least /dev/fd will exist
   1.126 +  static const char kFDDir[] = "/dev/fd";
   1.127 +#endif
   1.128 +
   1.129 +  // Get the maximum number of FDs possible.
   1.130 +  struct rlimit nofile;
   1.131 +  rlim_t max_fds;
   1.132 +  if (getrlimit(RLIMIT_NOFILE, &nofile)) {
   1.133 +    // getrlimit failed. Take a best guess.
   1.134 +    max_fds = kSystemDefaultMaxFds;
   1.135 +    DLOG(ERROR) << "getrlimit(RLIMIT_NOFILE) failed: " << errno;
   1.136 +  } else {
   1.137 +    max_fds = nofile.rlim_cur;
   1.138 +  }
   1.139 +
   1.140 +  if (max_fds > INT_MAX)
   1.141 +    max_fds = INT_MAX;
   1.142 +
   1.143 +  DirReaderPosix fd_dir(kFDDir);
   1.144 +
   1.145 +  if (!fd_dir.IsValid()) {
   1.146 +    // Fallback case: Try every possible fd.
   1.147 +    for (rlim_t i = 0; i < max_fds; ++i) {
   1.148 +      const int fd = static_cast<int>(i);
   1.149 +      if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
   1.150 +        continue;
   1.151 +      InjectiveMultimap::const_iterator j;
   1.152 +      for (j = saved_mapping.begin(); j != saved_mapping.end(); j++) {
   1.153 +        if (fd == j->dest)
   1.154 +          break;
   1.155 +      }
   1.156 +      if (j != saved_mapping.end())
   1.157 +        continue;
   1.158 +
   1.159 +      // Since we're just trying to close anything we can find,
   1.160 +      // ignore any error return values of close().
   1.161 +      HANDLE_EINTR(close(fd));
   1.162 +    }
   1.163 +    return;
   1.164 +  }
   1.165 +
   1.166 +  const int dir_fd = fd_dir.fd();
   1.167 +
   1.168 +  for ( ; fd_dir.Next(); ) {
   1.169 +    // Skip . and .. entries.
   1.170 +    if (fd_dir.name()[0] == '.')
   1.171 +      continue;
   1.172 +
   1.173 +    char *endptr;
   1.174 +    errno = 0;
   1.175 +    const long int fd = strtol(fd_dir.name(), &endptr, 10);
   1.176 +    if (fd_dir.name()[0] == 0 || *endptr || fd < 0 || errno)
   1.177 +      continue;
   1.178 +    if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
   1.179 +      continue;
   1.180 +    InjectiveMultimap::const_iterator i;
   1.181 +    for (i = saved_mapping.begin(); i != saved_mapping.end(); i++) {
   1.182 +      if (fd == i->dest)
   1.183 +        break;
   1.184 +    }
   1.185 +    if (i != saved_mapping.end())
   1.186 +      continue;
   1.187 +    if (fd == dir_fd)
   1.188 +      continue;
   1.189 +
   1.190 +    // When running under Valgrind, Valgrind opens several FDs for its
   1.191 +    // own use and will complain if we try to close them.  All of
   1.192 +    // these FDs are >= |max_fds|, so we can check against that here
   1.193 +    // before closing.  See https://bugs.kde.org/show_bug.cgi?id=191758
   1.194 +    if (fd < static_cast<int>(max_fds)) {
   1.195 +      int ret = HANDLE_EINTR(close(fd));
   1.196 +      if (ret != 0) {
   1.197 +        DLOG(ERROR) << "Problem closing fd";
   1.198 +      }
   1.199 +    }
   1.200 +  }
   1.201 +}
   1.202 +
   1.203 +// Sets all file descriptors to close on exec except for stdin, stdout
   1.204 +// and stderr.
   1.205 +// TODO(agl): Remove this function. It's fundamentally broken for multithreaded
   1.206 +// apps.
   1.207 +void SetAllFDsToCloseOnExec() {
   1.208 +#if defined(OS_LINUX)
   1.209 +  const char fd_dir[] = "/proc/self/fd";
   1.210 +#elif defined(OS_MACOSX) || defined(OS_BSD)
   1.211 +  const char fd_dir[] = "/dev/fd";
   1.212 +#endif
   1.213 +  ScopedDIR dir_closer(opendir(fd_dir));
   1.214 +  DIR *dir = dir_closer.get();
   1.215 +  if (NULL == dir) {
   1.216 +    DLOG(ERROR) << "Unable to open " << fd_dir;
   1.217 +    return;
   1.218 +  }
   1.219 +
   1.220 +  struct dirent *ent;
   1.221 +  while ((ent = readdir(dir))) {
   1.222 +    // Skip . and .. entries.
   1.223 +    if (ent->d_name[0] == '.')
   1.224 +      continue;
   1.225 +    int i = atoi(ent->d_name);
   1.226 +    // We don't close stdin, stdout or stderr.
   1.227 +    if (i <= STDERR_FILENO)
   1.228 +      continue;
   1.229 +
   1.230 +    int flags = fcntl(i, F_GETFD);
   1.231 +    if ((flags == -1) || (fcntl(i, F_SETFD, flags | FD_CLOEXEC) == -1)) {
   1.232 +      DLOG(ERROR) << "fcntl failure.";
   1.233 +    }
   1.234 +  }
   1.235 +}
   1.236 +
   1.237 +ProcessMetrics::ProcessMetrics(ProcessHandle process) : process_(process),
   1.238 +                                                        last_time_(0),
   1.239 +                                                        last_system_time_(0) {
   1.240 +  processor_count_ = base::SysInfo::NumberOfProcessors();
   1.241 +}
   1.242 +
   1.243 +// static
   1.244 +ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
   1.245 +  return new ProcessMetrics(process);
   1.246 +}
   1.247 +
   1.248 +ProcessMetrics::~ProcessMetrics() { }
   1.249 +
   1.250 +bool DidProcessCrash(bool* child_exited, ProcessHandle handle) {
   1.251 +  int status;
   1.252 +  const int result = HANDLE_EINTR(waitpid(handle, &status, WNOHANG));
   1.253 +  if (result == -1) {
   1.254 +    // This shouldn't happen, but sometimes it does.  The error is
   1.255 +    // probably ECHILD and the reason is probably that a pid was
   1.256 +    // waited on again after a previous wait reclaimed its zombie.
   1.257 +    // (It could also occur if the process isn't a direct child, but
   1.258 +    // don't do that.)  This is bad, because it risks interfering with
   1.259 +    // an unrelated child process if the pid is reused.
   1.260 +    //
   1.261 +    // So, lacking reliable information, we indicate that the process
   1.262 +    // is dead, in the hope that the caller will give up and stop
   1.263 +    // calling us.  See also bug 943174 and bug 933680.
   1.264 +    CHROMIUM_LOG(ERROR) << "waitpid failed pid:" << handle << " errno:" << errno;
   1.265 +    if (child_exited)
   1.266 +      *child_exited = true;
   1.267 +    return false;
   1.268 +  } else if (result == 0) {
   1.269 +    // the child hasn't exited yet.
   1.270 +    if (child_exited)
   1.271 +      *child_exited = false;
   1.272 +    return false;
   1.273 +  }
   1.274 +
   1.275 +  if (child_exited)
   1.276 +    *child_exited = true;
   1.277 +
   1.278 +  if (WIFSIGNALED(status)) {
   1.279 +    switch(WTERMSIG(status)) {
   1.280 +      case SIGSYS:
   1.281 +      case SIGSEGV:
   1.282 +      case SIGILL:
   1.283 +      case SIGABRT:
   1.284 +      case SIGFPE:
   1.285 +        return true;
   1.286 +      default:
   1.287 +        return false;
   1.288 +    }
   1.289 +  }
   1.290 +
   1.291 +  if (WIFEXITED(status))
   1.292 +    return WEXITSTATUS(status) != 0;
   1.293 +
   1.294 +  return false;
   1.295 +}
   1.296 +
   1.297 +namespace {
   1.298 +
   1.299 +int64_t TimeValToMicroseconds(const struct timeval& tv) {
   1.300 +  return tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec;
   1.301 +}
   1.302 +
   1.303 +}
   1.304 +
   1.305 +int ProcessMetrics::GetCPUUsage() {
   1.306 +  struct timeval now;
   1.307 +  struct rusage usage;
   1.308 +
   1.309 +  int retval = gettimeofday(&now, NULL);
   1.310 +  if (retval)
   1.311 +    return 0;
   1.312 +  retval = getrusage(RUSAGE_SELF, &usage);
   1.313 +  if (retval)
   1.314 +    return 0;
   1.315 +
   1.316 +  int64_t system_time = (TimeValToMicroseconds(usage.ru_stime) +
   1.317 +                       TimeValToMicroseconds(usage.ru_utime)) /
   1.318 +                        processor_count_;
   1.319 +  int64_t time = TimeValToMicroseconds(now);
   1.320 +
   1.321 +  if ((last_system_time_ == 0) || (last_time_ == 0)) {
   1.322 +    // First call, just set the last values.
   1.323 +    last_system_time_ = system_time;
   1.324 +    last_time_ = time;
   1.325 +    return 0;
   1.326 +  }
   1.327 +
   1.328 +  int64_t system_time_delta = system_time - last_system_time_;
   1.329 +  int64_t time_delta = time - last_time_;
   1.330 +  DCHECK(time_delta != 0);
   1.331 +  if (time_delta == 0)
   1.332 +    return 0;
   1.333 +
   1.334 +  // We add time_delta / 2 so the result is rounded.
   1.335 +  int cpu = static_cast<int>((system_time_delta * 100 + time_delta / 2) /
   1.336 +                             time_delta);
   1.337 +
   1.338 +  last_system_time_ = system_time;
   1.339 +  last_time_ = time;
   1.340 +
   1.341 +  return cpu;
   1.342 +}
   1.343 +
   1.344 +}  // namespace base

mercurial