michael@0: //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "base/basictypes.h" michael@0: #include "base/eintr_wrapper.h" michael@0: #include "base/logging.h" michael@0: #include "base/platform_thread.h" michael@0: #include "base/process_util.h" michael@0: #include "base/scoped_ptr.h" michael@0: #include "base/sys_info.h" michael@0: #include "base/time.h" michael@0: #include "base/waitable_event.h" michael@0: #include "base/dir_reader_posix.h" michael@0: michael@0: const int kMicrosecondsPerSecond = 1000000; michael@0: michael@0: namespace base { michael@0: michael@0: ProcessId GetCurrentProcId() { michael@0: return getpid(); michael@0: } michael@0: michael@0: ProcessHandle GetCurrentProcessHandle() { michael@0: return GetCurrentProcId(); michael@0: } michael@0: michael@0: bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) { michael@0: // On Posix platforms, process handles are the same as PIDs, so we michael@0: // don't need to do anything. michael@0: *handle = pid; michael@0: return true; michael@0: } michael@0: michael@0: bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) { michael@0: // On POSIX permissions are checked for each operation on process, michael@0: // not when opening a "handle". michael@0: return OpenProcessHandle(pid, handle); michael@0: } michael@0: michael@0: void CloseProcessHandle(ProcessHandle process) { michael@0: // See OpenProcessHandle, nothing to do. michael@0: return; michael@0: } michael@0: michael@0: ProcessId GetProcId(ProcessHandle process) { michael@0: return process; michael@0: } michael@0: michael@0: // Attempts to kill the process identified by the given process michael@0: // entry structure. Ignores specified exit_code; posix can't force that. michael@0: // Returns true if this is successful, false otherwise. michael@0: bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) { michael@0: bool result = kill(process_id, SIGTERM) == 0; michael@0: michael@0: if (result && wait) { michael@0: int tries = 60; michael@0: // The process may not end immediately due to pending I/O michael@0: while (tries-- > 0) { michael@0: int pid = HANDLE_EINTR(waitpid(process_id, NULL, WNOHANG)); michael@0: if (pid == process_id) michael@0: break; michael@0: michael@0: sleep(1); michael@0: } michael@0: michael@0: result = kill(process_id, SIGKILL) == 0; michael@0: } michael@0: michael@0: if (!result) michael@0: DLOG(ERROR) << "Unable to terminate process."; michael@0: michael@0: return result; michael@0: } michael@0: michael@0: #ifdef ANDROID michael@0: typedef unsigned long int rlim_t; michael@0: #endif michael@0: michael@0: // A class to handle auto-closing of DIR*'s. michael@0: class ScopedDIRClose { michael@0: public: michael@0: inline void operator()(DIR* x) const { michael@0: if (x) { michael@0: closedir(x); michael@0: } michael@0: } michael@0: }; michael@0: typedef scoped_ptr_malloc ScopedDIR; michael@0: michael@0: michael@0: void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) { michael@0: // DANGER: no calls to malloc are allowed from now on: michael@0: // http://crbug.com/36678 michael@0: #if defined(ANDROID) michael@0: static const rlim_t kSystemDefaultMaxFds = 1024; michael@0: static const char kFDDir[] = "/proc/self/fd"; michael@0: #elif defined(OS_LINUX) michael@0: static const rlim_t kSystemDefaultMaxFds = 8192; michael@0: static const char kFDDir[] = "/proc/self/fd"; michael@0: #elif defined(OS_MACOSX) michael@0: static const rlim_t kSystemDefaultMaxFds = 256; michael@0: static const char kFDDir[] = "/dev/fd"; michael@0: #elif defined(OS_BSD) michael@0: // the getrlimit below should never fail, so whatever .. michael@0: static const rlim_t kSystemDefaultMaxFds = 1024; michael@0: // at least /dev/fd will exist michael@0: static const char kFDDir[] = "/dev/fd"; michael@0: #endif michael@0: michael@0: // Get the maximum number of FDs possible. michael@0: struct rlimit nofile; michael@0: rlim_t max_fds; michael@0: if (getrlimit(RLIMIT_NOFILE, &nofile)) { michael@0: // getrlimit failed. Take a best guess. michael@0: max_fds = kSystemDefaultMaxFds; michael@0: DLOG(ERROR) << "getrlimit(RLIMIT_NOFILE) failed: " << errno; michael@0: } else { michael@0: max_fds = nofile.rlim_cur; michael@0: } michael@0: michael@0: if (max_fds > INT_MAX) michael@0: max_fds = INT_MAX; michael@0: michael@0: DirReaderPosix fd_dir(kFDDir); michael@0: michael@0: if (!fd_dir.IsValid()) { michael@0: // Fallback case: Try every possible fd. michael@0: for (rlim_t i = 0; i < max_fds; ++i) { michael@0: const int fd = static_cast(i); michael@0: if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) michael@0: continue; michael@0: InjectiveMultimap::const_iterator j; michael@0: for (j = saved_mapping.begin(); j != saved_mapping.end(); j++) { michael@0: if (fd == j->dest) michael@0: break; michael@0: } michael@0: if (j != saved_mapping.end()) michael@0: continue; michael@0: michael@0: // Since we're just trying to close anything we can find, michael@0: // ignore any error return values of close(). michael@0: HANDLE_EINTR(close(fd)); michael@0: } michael@0: return; michael@0: } michael@0: michael@0: const int dir_fd = fd_dir.fd(); michael@0: michael@0: for ( ; fd_dir.Next(); ) { michael@0: // Skip . and .. entries. michael@0: if (fd_dir.name()[0] == '.') michael@0: continue; michael@0: michael@0: char *endptr; michael@0: errno = 0; michael@0: const long int fd = strtol(fd_dir.name(), &endptr, 10); michael@0: if (fd_dir.name()[0] == 0 || *endptr || fd < 0 || errno) michael@0: continue; michael@0: if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) michael@0: continue; michael@0: InjectiveMultimap::const_iterator i; michael@0: for (i = saved_mapping.begin(); i != saved_mapping.end(); i++) { michael@0: if (fd == i->dest) michael@0: break; michael@0: } michael@0: if (i != saved_mapping.end()) michael@0: continue; michael@0: if (fd == dir_fd) michael@0: continue; michael@0: michael@0: // When running under Valgrind, Valgrind opens several FDs for its michael@0: // own use and will complain if we try to close them. All of michael@0: // these FDs are >= |max_fds|, so we can check against that here michael@0: // before closing. See https://bugs.kde.org/show_bug.cgi?id=191758 michael@0: if (fd < static_cast(max_fds)) { michael@0: int ret = HANDLE_EINTR(close(fd)); michael@0: if (ret != 0) { michael@0: DLOG(ERROR) << "Problem closing fd"; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Sets all file descriptors to close on exec except for stdin, stdout michael@0: // and stderr. michael@0: // TODO(agl): Remove this function. It's fundamentally broken for multithreaded michael@0: // apps. michael@0: void SetAllFDsToCloseOnExec() { michael@0: #if defined(OS_LINUX) michael@0: const char fd_dir[] = "/proc/self/fd"; michael@0: #elif defined(OS_MACOSX) || defined(OS_BSD) michael@0: const char fd_dir[] = "/dev/fd"; michael@0: #endif michael@0: ScopedDIR dir_closer(opendir(fd_dir)); michael@0: DIR *dir = dir_closer.get(); michael@0: if (NULL == dir) { michael@0: DLOG(ERROR) << "Unable to open " << fd_dir; michael@0: return; michael@0: } michael@0: michael@0: struct dirent *ent; michael@0: while ((ent = readdir(dir))) { michael@0: // Skip . and .. entries. michael@0: if (ent->d_name[0] == '.') michael@0: continue; michael@0: int i = atoi(ent->d_name); michael@0: // We don't close stdin, stdout or stderr. michael@0: if (i <= STDERR_FILENO) michael@0: continue; michael@0: michael@0: int flags = fcntl(i, F_GETFD); michael@0: if ((flags == -1) || (fcntl(i, F_SETFD, flags | FD_CLOEXEC) == -1)) { michael@0: DLOG(ERROR) << "fcntl failure."; michael@0: } michael@0: } michael@0: } michael@0: michael@0: ProcessMetrics::ProcessMetrics(ProcessHandle process) : process_(process), michael@0: last_time_(0), michael@0: last_system_time_(0) { michael@0: processor_count_ = base::SysInfo::NumberOfProcessors(); michael@0: } michael@0: michael@0: // static michael@0: ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) { michael@0: return new ProcessMetrics(process); michael@0: } michael@0: michael@0: ProcessMetrics::~ProcessMetrics() { } michael@0: michael@0: bool DidProcessCrash(bool* child_exited, ProcessHandle handle) { michael@0: int status; michael@0: const int result = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); michael@0: if (result == -1) { michael@0: // This shouldn't happen, but sometimes it does. The error is michael@0: // probably ECHILD and the reason is probably that a pid was michael@0: // waited on again after a previous wait reclaimed its zombie. michael@0: // (It could also occur if the process isn't a direct child, but michael@0: // don't do that.) This is bad, because it risks interfering with michael@0: // an unrelated child process if the pid is reused. michael@0: // michael@0: // So, lacking reliable information, we indicate that the process michael@0: // is dead, in the hope that the caller will give up and stop michael@0: // calling us. See also bug 943174 and bug 933680. michael@0: CHROMIUM_LOG(ERROR) << "waitpid failed pid:" << handle << " errno:" << errno; michael@0: if (child_exited) michael@0: *child_exited = true; michael@0: return false; michael@0: } else if (result == 0) { michael@0: // the child hasn't exited yet. michael@0: if (child_exited) michael@0: *child_exited = false; michael@0: return false; michael@0: } michael@0: michael@0: if (child_exited) michael@0: *child_exited = true; michael@0: michael@0: if (WIFSIGNALED(status)) { michael@0: switch(WTERMSIG(status)) { michael@0: case SIGSYS: michael@0: case SIGSEGV: michael@0: case SIGILL: michael@0: case SIGABRT: michael@0: case SIGFPE: michael@0: return true; michael@0: default: michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: if (WIFEXITED(status)) michael@0: return WEXITSTATUS(status) != 0; michael@0: michael@0: return false; michael@0: } michael@0: michael@0: namespace { michael@0: michael@0: int64_t TimeValToMicroseconds(const struct timeval& tv) { michael@0: return tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec; michael@0: } michael@0: michael@0: } michael@0: michael@0: int ProcessMetrics::GetCPUUsage() { michael@0: struct timeval now; michael@0: struct rusage usage; michael@0: michael@0: int retval = gettimeofday(&now, NULL); michael@0: if (retval) michael@0: return 0; michael@0: retval = getrusage(RUSAGE_SELF, &usage); michael@0: if (retval) michael@0: return 0; michael@0: michael@0: int64_t system_time = (TimeValToMicroseconds(usage.ru_stime) + michael@0: TimeValToMicroseconds(usage.ru_utime)) / michael@0: processor_count_; michael@0: int64_t time = TimeValToMicroseconds(now); michael@0: michael@0: if ((last_system_time_ == 0) || (last_time_ == 0)) { michael@0: // First call, just set the last values. michael@0: last_system_time_ = system_time; michael@0: last_time_ = time; michael@0: return 0; michael@0: } michael@0: michael@0: int64_t system_time_delta = system_time - last_system_time_; michael@0: int64_t time_delta = time - last_time_; michael@0: DCHECK(time_delta != 0); michael@0: if (time_delta == 0) michael@0: return 0; michael@0: michael@0: // We add time_delta / 2 so the result is rounded. michael@0: int cpu = static_cast((system_time_delta * 100 + time_delta / 2) / michael@0: time_delta); michael@0: michael@0: last_system_time_ = system_time; michael@0: last_time_ = time; michael@0: michael@0: return cpu; michael@0: } michael@0: michael@0: } // namespace base