summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorrsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-31 15:38:01 +0000
committerrsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-31 15:38:01 +0000
commitd3acb67574294e4e0b3b74840558ef81ebb433b5 (patch)
tree84472dcdaf777dfdecd1644e2256bd985d791f3d /base
parent52325b2a52aa5ea3adab9edbab67a10380c08618 (diff)
downloadchromium_src-d3acb67574294e4e0b3b74840558ef81ebb433b5.zip
chromium_src-d3acb67574294e4e0b3b74840558ef81ebb433b5.tar.gz
chromium_src-d3acb67574294e4e0b3b74840558ef81ebb433b5.tar.bz2
Split ProcessIterator and friends out of base/process_util.h into base/process/process_iterator.h.
BUG=242290 R=brettw@chromium.org Review URL: https://codereview.chromium.org/15806006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@203412 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r--base/base.gypi13
-rw-r--r--base/process/process_iterator.cc65
-rw-r--r--base/process/process_iterator.h183
-rw-r--r--base/process/process_iterator_freebsd.cc124
-rw-r--r--base/process/process_iterator_linux.cc138
-rw-r--r--base/process/process_iterator_mac.cc134
-rw-r--r--base/process/process_iterator_openbsd.cc128
-rw-r--r--base/process/process_iterator_win.cc41
-rw-r--r--base/process_util.cc56
-rw-r--r--base/process_util.h155
-rw-r--r--base/process_util_freebsd.cc110
-rw-r--r--base/process_util_linux.cc123
-rw-r--r--base/process_util_mac.mm117
-rw-r--r--base/process_util_openbsd.cc114
-rw-r--r--base/process_util_win.cc32
15 files changed, 825 insertions, 708 deletions
diff --git a/base/base.gypi b/base/base.gypi
index 8b1e93d..456bcb3 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -377,6 +377,15 @@
'process_util_posix.cc',
'process_util_win.cc',
'process_win.cc',
+ 'process/internal_linux.cc',
+ 'process/internal_linux.h',
+ 'process/process_iterator.cc',
+ 'process/process_iterator.h',
+ 'process/process_iterator_freebsd.cc',
+ 'process/process_iterator_linux.cc',
+ 'process/process_iterator_mac.cc',
+ 'process/process_iterator_openbsd.cc',
+ 'process/process_iterator_win.cc',
'process/process_metrics.h',
'process/process_metrics_freebsd.cc',
'process/process_metrics_ios.cc',
@@ -385,8 +394,6 @@
'process/process_metrics_openbsd.cc',
'process/process_metrics_posix.cc',
'process/process_metrics_win.cc',
- 'process/internal_linux.cc',
- 'process/internal_linux.h',
'profiler/scoped_profile.cc',
'profiler/scoped_profile.h',
'profiler/alternate_timer.cc',
@@ -689,6 +696,8 @@
['include', '^files/file_path_watcher_linux\\.cc$'],
['include', '^process_util_linux\\.cc$'],
['include', '^process/internal_linux\\.cc$'],
+ ['include', '^process/process_iterator\\.cc$'],
+ ['include', '^process/process_iterator_linux\\.cc$'],
['include', '^process/process_metrics_linux\\.cc$'],
['include', '^posix/unix_domain_socket_linux\\.cc$'],
['include', '^strings/sys_string_conversions_posix\\.cc$'],
diff --git a/base/process/process_iterator.cc b/base/process/process_iterator.cc
new file mode 100644
index 0000000..b9ef047
--- /dev/null
+++ b/base/process/process_iterator.cc
@@ -0,0 +1,65 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_iterator.h"
+
+namespace base {
+
+#if defined(OS_POSIX)
+ProcessEntry::ProcessEntry() : pid_(0), ppid_(0), gid_(0) {}
+ProcessEntry::~ProcessEntry() {}
+#endif
+
+const ProcessEntry* ProcessIterator::NextProcessEntry() {
+ bool result = false;
+ do {
+ result = CheckForNextProcess();
+ } while (result && !IncludeEntry());
+ if (result)
+ return &entry_;
+ return NULL;
+}
+
+ProcessIterator::ProcessEntries ProcessIterator::Snapshot() {
+ ProcessEntries found;
+ while (const ProcessEntry* process_entry = NextProcessEntry()) {
+ found.push_back(*process_entry);
+ }
+ return found;
+}
+
+bool ProcessIterator::IncludeEntry() {
+ return !filter_ || filter_->Includes(entry_);
+}
+
+NamedProcessIterator::NamedProcessIterator(
+ const FilePath::StringType& executable_name,
+ const ProcessFilter* filter) : ProcessIterator(filter),
+ executable_name_(executable_name) {
+#if defined(OS_ANDROID)
+ // On Android, the process name contains only the last 15 characters, which
+ // is in file /proc/<pid>/stat, the string between open parenthesis and close
+ // parenthesis. Please See ProcessIterator::CheckForNextProcess for details.
+ // Now if the length of input process name is greater than 15, only save the
+ // last 15 characters.
+ if (executable_name_.size() > 15) {
+ executable_name_ = FilePath::StringType(executable_name_,
+ executable_name_.size() - 15, 15);
+ }
+#endif
+}
+
+NamedProcessIterator::~NamedProcessIterator() {
+}
+
+int GetProcessCount(const FilePath::StringType& executable_name,
+ const ProcessFilter* filter) {
+ int count = 0;
+ NamedProcessIterator iter(executable_name, filter);
+ while (iter.NextProcessEntry())
+ ++count;
+ return count;
+}
+
+} // namespace base
diff --git a/base/process/process_iterator.h b/base/process/process_iterator.h
new file mode 100644
index 0000000..f8ab2a2
--- /dev/null
+++ b/base/process/process_iterator.h
@@ -0,0 +1,183 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains methods to iterate over processes on the system.
+
+#ifndef BASE_PROCESS_PROCESS_ITERATOR_H_
+#define BASE_PROCESS_PROCESS_ITERATOR_H_
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include "build/build_config.h"
+#include "base/basictypes.h"
+#include "base/base_export.h"
+#include "base/files/file_path.h"
+#include "base/process.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <tlhelp32.h>
+#elif defined(OS_MACOSX) || defined(OS_BSD)
+#include <sys/sysctl.h>
+#elif defined(OS_POSIX)
+#include <dirent.h>
+#endif
+
+namespace base {
+
+#if defined(OS_WIN)
+struct ProcessEntry : public PROCESSENTRY32 {
+ ProcessId pid() const { return th32ProcessID; }
+ ProcessId parent_pid() const { return th32ParentProcessID; }
+ const wchar_t* exe_file() const { return szExeFile; }
+};
+
+// Process access masks. These constants provide platform-independent
+// definitions for the standard Windows access masks.
+// See http://msdn.microsoft.com/en-us/library/ms684880(VS.85).aspx for
+// the specific semantics of each mask value.
+const uint32 kProcessAccessTerminate = PROCESS_TERMINATE;
+const uint32 kProcessAccessCreateThread = PROCESS_CREATE_THREAD;
+const uint32 kProcessAccessSetSessionId = PROCESS_SET_SESSIONID;
+const uint32 kProcessAccessVMOperation = PROCESS_VM_OPERATION;
+const uint32 kProcessAccessVMRead = PROCESS_VM_READ;
+const uint32 kProcessAccessVMWrite = PROCESS_VM_WRITE;
+const uint32 kProcessAccessDuplicateHandle = PROCESS_DUP_HANDLE;
+const uint32 kProcessAccessCreateProcess = PROCESS_CREATE_PROCESS;
+const uint32 kProcessAccessSetQuota = PROCESS_SET_QUOTA;
+const uint32 kProcessAccessSetInformation = PROCESS_SET_INFORMATION;
+const uint32 kProcessAccessQueryInformation = PROCESS_QUERY_INFORMATION;
+const uint32 kProcessAccessSuspendResume = PROCESS_SUSPEND_RESUME;
+const uint32 kProcessAccessQueryLimitedInfomation =
+ PROCESS_QUERY_LIMITED_INFORMATION;
+const uint32 kProcessAccessWaitForTermination = SYNCHRONIZE;
+#elif defined(OS_POSIX)
+struct BASE_EXPORT ProcessEntry {
+ ProcessEntry();
+ ~ProcessEntry();
+
+ ProcessId pid() const { return pid_; }
+ ProcessId parent_pid() const { return ppid_; }
+ ProcessId gid() const { return gid_; }
+ const char* exe_file() const { return exe_file_.c_str(); }
+ const std::vector<std::string>& cmd_line_args() const {
+ return cmd_line_args_;
+ }
+
+ ProcessId pid_;
+ ProcessId ppid_;
+ ProcessId gid_;
+ std::string exe_file_;
+ std::vector<std::string> cmd_line_args_;
+};
+
+// Process access masks. They are not used on Posix because access checking
+// does not happen during handle creation.
+const uint32 kProcessAccessTerminate = 0;
+const uint32 kProcessAccessCreateThread = 0;
+const uint32 kProcessAccessSetSessionId = 0;
+const uint32 kProcessAccessVMOperation = 0;
+const uint32 kProcessAccessVMRead = 0;
+const uint32 kProcessAccessVMWrite = 0;
+const uint32 kProcessAccessDuplicateHandle = 0;
+const uint32 kProcessAccessCreateProcess = 0;
+const uint32 kProcessAccessSetQuota = 0;
+const uint32 kProcessAccessSetInformation = 0;
+const uint32 kProcessAccessQueryInformation = 0;
+const uint32 kProcessAccessSuspendResume = 0;
+const uint32 kProcessAccessQueryLimitedInfomation = 0;
+const uint32 kProcessAccessWaitForTermination = 0;
+#endif // defined(OS_POSIX)
+
+// Used to filter processes by process ID.
+class ProcessFilter {
+ public:
+ // Returns true to indicate set-inclusion and false otherwise. This method
+ // should not have side-effects and should be idempotent.
+ virtual bool Includes(const ProcessEntry& entry) const = 0;
+
+ protected:
+ virtual ~ProcessFilter() {}
+};
+
+// This class provides a way to iterate through a list of processes on the
+// current machine with a specified filter.
+// To use, create an instance and then call NextProcessEntry() until it returns
+// false.
+class BASE_EXPORT ProcessIterator {
+ public:
+ typedef std::list<ProcessEntry> ProcessEntries;
+
+ explicit ProcessIterator(const ProcessFilter* filter);
+ virtual ~ProcessIterator();
+
+ // If there's another process that matches the given executable name,
+ // returns a const pointer to the corresponding PROCESSENTRY32.
+ // If there are no more matching processes, returns NULL.
+ // The returned pointer will remain valid until NextProcessEntry()
+ // is called again or this NamedProcessIterator goes out of scope.
+ const ProcessEntry* NextProcessEntry();
+
+ // Takes a snapshot of all the ProcessEntry found.
+ ProcessEntries Snapshot();
+
+ protected:
+ virtual bool IncludeEntry();
+ const ProcessEntry& entry() { return entry_; }
+
+ private:
+ // Determines whether there's another process (regardless of executable)
+ // left in the list of all processes. Returns true and sets entry_ to
+ // that process's info if there is one, false otherwise.
+ bool CheckForNextProcess();
+
+ // Initializes a PROCESSENTRY32 data structure so that it's ready for
+ // use with Process32First/Process32Next.
+ void InitProcessEntry(ProcessEntry* entry);
+
+#if defined(OS_WIN)
+ HANDLE snapshot_;
+ bool started_iteration_;
+#elif defined(OS_MACOSX) || defined(OS_BSD)
+ std::vector<kinfo_proc> kinfo_procs_;
+ size_t index_of_kinfo_proc_;
+#elif defined(OS_POSIX)
+ DIR* procfs_dir_;
+#endif
+ ProcessEntry entry_;
+ const ProcessFilter* filter_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProcessIterator);
+};
+
+// This class provides a way to iterate through the list of processes
+// on the current machine that were started from the given executable
+// name. To use, create an instance and then call NextProcessEntry()
+// until it returns false.
+class BASE_EXPORT NamedProcessIterator : public ProcessIterator {
+ public:
+ NamedProcessIterator(const FilePath::StringType& executable_name,
+ const ProcessFilter* filter);
+ virtual ~NamedProcessIterator();
+
+ protected:
+ virtual bool IncludeEntry() OVERRIDE;
+
+ private:
+ FilePath::StringType executable_name_;
+
+ DISALLOW_COPY_AND_ASSIGN(NamedProcessIterator);
+};
+
+// Returns the number of processes on the machine that are running from the
+// given executable name. If filter is non-null, then only processes selected
+// by the filter will be counted.
+BASE_EXPORT int GetProcessCount(const FilePath::StringType& executable_name,
+ const ProcessFilter* filter);
+
+} // namespace base
+
+#endif // BASE_PROCESS_PROCESS_ITERATOR_H_
diff --git a/base/process/process_iterator_freebsd.cc b/base/process/process_iterator_freebsd.cc
new file mode 100644
index 0000000..408ce8d
--- /dev/null
+++ b/base/process/process_iterator_freebsd.cc
@@ -0,0 +1,124 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_iterator.h"
+
+#include <sys/sysctl.h>
+
+#include "base/logging.h"
+#include "base/string_util.h"
+
+namespace base {
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+ : index_of_kinfo_proc_(),
+ filter_(filter) {
+
+ int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, getuid() };
+
+ bool done = false;
+ int try_num = 1;
+ const int max_tries = 10;
+
+ do {
+ size_t len = 0;
+ if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) {
+ LOG(ERROR) << "failed to get the size needed for the process list";
+ kinfo_procs_.resize(0);
+ done = true;
+ } else {
+ size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+ // Leave some spare room for process table growth (more could show up
+ // between when we check and now)
+ num_of_kinfo_proc += 16;
+ kinfo_procs_.resize(num_of_kinfo_proc);
+ len = num_of_kinfo_proc * sizeof(struct kinfo_proc);
+ if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) <0) {
+ // If we get a mem error, it just means we need a bigger buffer, so
+ // loop around again. Anything else is a real error and give up.
+ if (errno != ENOMEM) {
+ LOG(ERROR) << "failed to get the process list";
+ kinfo_procs_.resize(0);
+ done = true;
+ }
+ } else {
+ // Got the list, just make sure we're sized exactly right
+ size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+ kinfo_procs_.resize(num_of_kinfo_proc);
+ done = true;
+ }
+ }
+ } while (!done && (try_num++ < max_tries));
+
+ if (!done) {
+ LOG(ERROR) << "failed to collect the process list in a few tries";
+ kinfo_procs_.resize(0);
+ }
+}
+
+ProcessIterator::~ProcessIterator() {
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+ std::string data;
+
+ for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
+ size_t length;
+ struct kinfo_proc kinfo = kinfo_procs_[index_of_kinfo_proc_];
+ int mib[] = { CTL_KERN, KERN_PROC_ARGS, kinfo.ki_pid };
+
+ if ((kinfo.ki_pid > 0) && (kinfo.ki_stat == SZOMB))
+ continue;
+
+ length = 0;
+ if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0) {
+ LOG(ERROR) << "failed to figure out the buffer size for a command line";
+ continue;
+ }
+
+ data.resize(length);
+
+ if (sysctl(mib, arraysize(mib), &data[0], &length, NULL, 0) < 0) {
+ LOG(ERROR) << "failed to fetch a commandline";
+ continue;
+ }
+
+ std::string delimiters;
+ delimiters.push_back('\0');
+ Tokenize(data, delimiters, &entry_.cmd_line_args_);
+
+ size_t exec_name_end = data.find('\0');
+ if (exec_name_end == std::string::npos) {
+ LOG(ERROR) << "command line data didn't match expected format";
+ continue;
+ }
+
+ entry_.pid_ = kinfo.ki_pid;
+ entry_.ppid_ = kinfo.ki_ppid;
+ entry_.gid_ = kinfo.ki_pgid;
+
+ size_t last_slash = data.rfind('/', exec_name_end);
+ if (last_slash == std::string::npos) {
+ entry_.exe_file_.assign(data, 0, exec_name_end);
+ } else {
+ entry_.exe_file_.assign(data, last_slash + 1,
+ exec_name_end - last_slash - 1);
+ }
+
+ // Start w/ the next entry next time through
+ ++index_of_kinfo_proc_;
+
+ return true;
+ }
+ return false;
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+ if (executable_name_ != entry().exe_file())
+ return false;
+
+ return ProcessIterator::IncludeEntry();
+}
+
+} // namespace base
diff --git a/base/process/process_iterator_linux.cc b/base/process/process_iterator_linux.cc
new file mode 100644
index 0000000..94925d4
--- /dev/null
+++ b/base/process/process_iterator_linux.cc
@@ -0,0 +1,138 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_iterator.h"
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/process/internal_linux.h"
+#include "base/process_util.h"
+#include "base/string_util.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+namespace {
+
+// Reads the |field_num|th field from |proc_stats|.
+// Returns an empty string on failure.
+// This version only handles VM_COMM and VM_STATE, which are the only fields
+// that are strings.
+std::string GetProcStatsFieldAsString(
+ const std::vector<std::string>& proc_stats,
+ internal::ProcStatsFields field_num) {
+ if (field_num < internal::VM_COMM || field_num > internal::VM_STATE) {
+ NOTREACHED();
+ return std::string();
+ }
+
+ if (proc_stats.size() > static_cast<size_t>(field_num))
+ return proc_stats[field_num];
+
+ NOTREACHED();
+ return 0;
+}
+
+// Reads /proc/<pid>/cmdline and populates |proc_cmd_line_args| with the command
+// line arguments. Returns true if successful.
+// Note: /proc/<pid>/cmdline contains command line arguments separated by single
+// null characters. We tokenize it into a vector of strings using '\0' as a
+// delimiter.
+bool GetProcCmdline(pid_t pid, std::vector<std::string>* proc_cmd_line_args) {
+ // Synchronously reading files in /proc is safe.
+ ThreadRestrictions::ScopedAllowIO allow_io;
+
+ FilePath cmd_line_file = internal::GetProcPidDir(pid).Append("cmdline");
+ std::string cmd_line;
+ if (!file_util::ReadFileToString(cmd_line_file, &cmd_line))
+ return false;
+ std::string delimiters;
+ delimiters.push_back('\0');
+ Tokenize(cmd_line, delimiters, proc_cmd_line_args);
+ return true;
+}
+
+} // namespace
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+ : filter_(filter) {
+ procfs_dir_ = opendir(internal::kProcDir);
+}
+
+ProcessIterator::~ProcessIterator() {
+ if (procfs_dir_) {
+ closedir(procfs_dir_);
+ procfs_dir_ = NULL;
+ }
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+ // TODO(port): skip processes owned by different UID
+
+ pid_t pid = kNullProcessId;
+ std::vector<std::string> cmd_line_args;
+ std::string stats_data;
+ std::vector<std::string> proc_stats;
+
+ // Arbitrarily guess that there will never be more than 200 non-process
+ // files in /proc. Hardy has 53 and Lucid has 61.
+ int skipped = 0;
+ const int kSkipLimit = 200;
+ while (skipped < kSkipLimit) {
+ dirent* slot = readdir(procfs_dir_);
+ // all done looking through /proc?
+ if (!slot)
+ return false;
+
+ // If not a process, keep looking for one.
+ pid = internal::ProcDirSlotToPid(slot->d_name);
+ if (!pid) {
+ skipped++;
+ continue;
+ }
+
+ if (!GetProcCmdline(pid, &cmd_line_args))
+ continue;
+
+ if (!internal::ReadProcStats(pid, &stats_data))
+ continue;
+ if (!internal::ParseProcStats(stats_data, &proc_stats))
+ continue;
+
+ std::string runstate =
+ GetProcStatsFieldAsString(proc_stats, internal::VM_STATE);
+ if (runstate.size() != 1) {
+ NOTREACHED();
+ continue;
+ }
+
+ // Is the process in 'Zombie' state, i.e. dead but waiting to be reaped?
+ // Allowed values: D R S T Z
+ if (runstate[0] != 'Z')
+ break;
+
+ // Nope, it's a zombie; somebody isn't cleaning up after their children.
+ // (e.g. WaitForProcessesToExit doesn't clean up after dead children yet.)
+ // There could be a lot of zombies, can't really decrement i here.
+ }
+ if (skipped >= kSkipLimit) {
+ NOTREACHED();
+ return false;
+ }
+
+ entry_.pid_ = pid;
+ entry_.ppid_ = GetProcStatsFieldAsInt(proc_stats, internal::VM_PPID);
+ entry_.gid_ = GetProcStatsFieldAsInt(proc_stats, internal::VM_PGRP);
+ entry_.cmd_line_args_.assign(cmd_line_args.begin(), cmd_line_args.end());
+ entry_.exe_file_ = GetProcessExecutablePath(pid).BaseName().value();
+ return true;
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+ if (executable_name_ != entry().exe_file())
+ return false;
+ return ProcessIterator::IncludeEntry();
+}
+
+} // namespace base
diff --git a/base/process/process_iterator_mac.cc b/base/process/process_iterator_mac.cc
new file mode 100644
index 0000000..1cc9b25
--- /dev/null
+++ b/base/process/process_iterator_mac.cc
@@ -0,0 +1,134 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_iterator.h"
+
+#include <errno.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include "base/logging.h"
+#include "base/string_util.h"
+
+namespace base {
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+ : index_of_kinfo_proc_(0),
+ filter_(filter) {
+ // Get a snapshot of all of my processes (yes, as we loop it can go stale, but
+ // but trying to find where we were in a constantly changing list is basically
+ // impossible.
+
+ int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, geteuid() };
+
+ // Since more processes could start between when we get the size and when
+ // we get the list, we do a loop to keep trying until we get it.
+ bool done = false;
+ int try_num = 1;
+ const int max_tries = 10;
+ do {
+ // Get the size of the buffer
+ size_t len = 0;
+ if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) {
+ DLOG(ERROR) << "failed to get the size needed for the process list";
+ kinfo_procs_.resize(0);
+ done = true;
+ } else {
+ size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+ // Leave some spare room for process table growth (more could show up
+ // between when we check and now)
+ num_of_kinfo_proc += 16;
+ kinfo_procs_.resize(num_of_kinfo_proc);
+ len = num_of_kinfo_proc * sizeof(struct kinfo_proc);
+ // Load the list of processes
+ if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) < 0) {
+ // If we get a mem error, it just means we need a bigger buffer, so
+ // loop around again. Anything else is a real error and give up.
+ if (errno != ENOMEM) {
+ DLOG(ERROR) << "failed to get the process list";
+ kinfo_procs_.resize(0);
+ done = true;
+ }
+ } else {
+ // Got the list, just make sure we're sized exactly right
+ size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+ kinfo_procs_.resize(num_of_kinfo_proc);
+ done = true;
+ }
+ }
+ } while (!done && (try_num++ < max_tries));
+
+ if (!done) {
+ DLOG(ERROR) << "failed to collect the process list in a few tries";
+ kinfo_procs_.resize(0);
+ }
+}
+
+ProcessIterator::~ProcessIterator() {
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+ std::string data;
+ for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
+ kinfo_proc& kinfo = kinfo_procs_[index_of_kinfo_proc_];
+
+ // Skip processes just awaiting collection
+ if ((kinfo.kp_proc.p_pid > 0) && (kinfo.kp_proc.p_stat == SZOMB))
+ continue;
+
+ int mib[] = { CTL_KERN, KERN_PROCARGS, kinfo.kp_proc.p_pid };
+
+ // Find out what size buffer we need.
+ size_t data_len = 0;
+ if (sysctl(mib, arraysize(mib), NULL, &data_len, NULL, 0) < 0) {
+ DVPLOG(1) << "failed to figure out the buffer size for a commandline";
+ continue;
+ }
+
+ data.resize(data_len);
+ if (sysctl(mib, arraysize(mib), &data[0], &data_len, NULL, 0) < 0) {
+ DVPLOG(1) << "failed to fetch a commandline";
+ continue;
+ }
+
+ // |data| contains all the command line parameters of the process, separated
+ // by blocks of one or more null characters. We tokenize |data| into a
+ // vector of strings using '\0' as a delimiter and populate
+ // |entry_.cmd_line_args_|.
+ std::string delimiters;
+ delimiters.push_back('\0');
+ Tokenize(data, delimiters, &entry_.cmd_line_args_);
+
+ // |data| starts with the full executable path followed by a null character.
+ // We search for the first instance of '\0' and extract everything before it
+ // to populate |entry_.exe_file_|.
+ size_t exec_name_end = data.find('\0');
+ if (exec_name_end == std::string::npos) {
+ DLOG(ERROR) << "command line data didn't match expected format";
+ continue;
+ }
+
+ entry_.pid_ = kinfo.kp_proc.p_pid;
+ entry_.ppid_ = kinfo.kp_eproc.e_ppid;
+ entry_.gid_ = kinfo.kp_eproc.e_pgid;
+ size_t last_slash = data.rfind('/', exec_name_end);
+ if (last_slash == std::string::npos)
+ entry_.exe_file_.assign(data, 0, exec_name_end);
+ else
+ entry_.exe_file_.assign(data, last_slash + 1,
+ exec_name_end - last_slash - 1);
+ // Start w/ the next entry next time through
+ ++index_of_kinfo_proc_;
+ // Done
+ return true;
+ }
+ return false;
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+ return (executable_name_ == entry().exe_file() &&
+ ProcessIterator::IncludeEntry());
+}
+
+} // namespace base
diff --git a/base/process/process_iterator_openbsd.cc b/base/process/process_iterator_openbsd.cc
new file mode 100644
index 0000000..b52ddcb
--- /dev/null
+++ b/base/process/process_iterator_openbsd.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_iterator.h"
+
+#include <errno.h>
+#include <sys/sysctl.h>
+
+#include "base/logging.h"
+#include "base/string_util.h"
+
+namespace base {
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+ : index_of_kinfo_proc_(),
+ filter_(filter) {
+
+ int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, getuid(),
+ sizeof(struct kinfo_proc), 0 };
+
+ bool done = false;
+ int try_num = 1;
+ const int max_tries = 10;
+
+ do {
+ size_t len = 0;
+ if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) {
+ DLOG(ERROR) << "failed to get the size needed for the process list";
+ kinfo_procs_.resize(0);
+ done = true;
+ } else {
+ size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+ // Leave some spare room for process table growth (more could show up
+ // between when we check and now)
+ num_of_kinfo_proc += 16;
+ kinfo_procs_.resize(num_of_kinfo_proc);
+ len = num_of_kinfo_proc * sizeof(struct kinfo_proc);
+ if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) < 0) {
+ // If we get a mem error, it just means we need a bigger buffer, so
+ // loop around again. Anything else is a real error and give up.
+ if (errno != ENOMEM) {
+ DLOG(ERROR) << "failed to get the process list";
+ kinfo_procs_.resize(0);
+ done = true;
+ }
+ } else {
+ // Got the list, just make sure we're sized exactly right
+ size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+ kinfo_procs_.resize(num_of_kinfo_proc);
+ done = true;
+ }
+ }
+ } while (!done && (try_num++ < max_tries));
+
+ if (!done) {
+ DLOG(ERROR) << "failed to collect the process list in a few tries";
+ kinfo_procs_.resize(0);
+ }
+}
+
+ProcessIterator::~ProcessIterator() {
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+ std::string data;
+ for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
+ kinfo_proc& kinfo = kinfo_procs_[index_of_kinfo_proc_];
+
+ // Skip processes just awaiting collection
+ if ((kinfo.p_pid > 0) && (kinfo.p_stat == SZOMB))
+ continue;
+
+ int mib[] = { CTL_KERN, KERN_PROC_ARGS, kinfo.p_pid };
+
+ // Find out what size buffer we need.
+ size_t data_len = 0;
+ if (sysctl(mib, arraysize(mib), NULL, &data_len, NULL, 0) < 0) {
+ DVPLOG(1) << "failed to figure out the buffer size for a commandline";
+ continue;
+ }
+
+ data.resize(data_len);
+ if (sysctl(mib, arraysize(mib), &data[0], &data_len, NULL, 0) < 0) {
+ DVPLOG(1) << "failed to fetch a commandline";
+ continue;
+ }
+
+ // |data| contains all the command line parameters of the process, separated
+ // by blocks of one or more null characters. We tokenize |data| into a
+ // vector of strings using '\0' as a delimiter and populate
+ // |entry_.cmd_line_args_|.
+ std::string delimiters;
+ delimiters.push_back('\0');
+ Tokenize(data, delimiters, &entry_.cmd_line_args_);
+
+ // |data| starts with the full executable path followed by a null character.
+ // We search for the first instance of '\0' and extract everything before it
+ // to populate |entry_.exe_file_|.
+ size_t exec_name_end = data.find('\0');
+ if (exec_name_end == std::string::npos) {
+ DLOG(ERROR) << "command line data didn't match expected format";
+ continue;
+ }
+
+ entry_.pid_ = kinfo.p_pid;
+ entry_.ppid_ = kinfo.p_ppid;
+ entry_.gid_ = kinfo.p__pgid;
+ size_t last_slash = data.rfind('/', exec_name_end);
+ if (last_slash == std::string::npos)
+ entry_.exe_file_.assign(data, 0, exec_name_end);
+ else
+ entry_.exe_file_.assign(data, last_slash + 1,
+ exec_name_end - last_slash - 1);
+ // Start w/ the next entry next time through
+ ++index_of_kinfo_proc_;
+ // Done
+ return true;
+ }
+ return false;
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+ return (executable_name_ == entry().exe_file() &&
+ ProcessIterator::IncludeEntry());
+}
+
+} // namespace base
diff --git a/base/process/process_iterator_win.cc b/base/process/process_iterator_win.cc
new file mode 100644
index 0000000..9d5a970
--- /dev/null
+++ b/base/process/process_iterator_win.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_iterator.h"
+
+namespace base {
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+ : started_iteration_(false),
+ filter_(filter) {
+ snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+}
+
+ProcessIterator::~ProcessIterator() {
+ CloseHandle(snapshot_);
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+ InitProcessEntry(&entry_);
+
+ if (!started_iteration_) {
+ started_iteration_ = true;
+ return !!Process32First(snapshot_, &entry_);
+ }
+
+ return !!Process32Next(snapshot_, &entry_);
+}
+
+void ProcessIterator::InitProcessEntry(ProcessEntry* entry) {
+ memset(entry, 0, sizeof(*entry));
+ entry->dwSize = sizeof(*entry);
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+ // Case insensitive.
+ return _wcsicmp(executable_name_.c_str(), entry().exe_file()) == 0 &&
+ ProcessIterator::IncludeEntry();
+}
+
+} // namespace base
diff --git a/base/process_util.cc b/base/process_util.cc
index 9979dfa..9b89c8f 100644
--- a/base/process_util.cc
+++ b/base/process_util.cc
@@ -6,20 +6,6 @@
namespace base {
-#if defined(OS_POSIX)
-ProcessEntry::ProcessEntry() : pid_(0), ppid_(0), gid_(0) {}
-ProcessEntry::~ProcessEntry() {}
-#endif
-
-int GetProcessCount(const FilePath::StringType& executable_name,
- const ProcessFilter* filter) {
- int count = 0;
- NamedProcessIterator iter(executable_name, filter);
- while (iter.NextProcessEntry())
- ++count;
- return count;
-}
-
bool KillProcesses(const FilePath::StringType& executable_name, int exit_code,
const ProcessFilter* filter) {
bool result = true;
@@ -34,46 +20,4 @@ bool KillProcesses(const FilePath::StringType& executable_name, int exit_code,
return result;
}
-const ProcessEntry* ProcessIterator::NextProcessEntry() {
- bool result = false;
- do {
- result = CheckForNextProcess();
- } while (result && !IncludeEntry());
- if (result)
- return &entry_;
- return NULL;
-}
-
-ProcessIterator::ProcessEntries ProcessIterator::Snapshot() {
- ProcessEntries found;
- while (const ProcessEntry* process_entry = NextProcessEntry()) {
- found.push_back(*process_entry);
- }
- return found;
-}
-
-bool ProcessIterator::IncludeEntry() {
- return !filter_ || filter_->Includes(entry_);
-}
-
-NamedProcessIterator::NamedProcessIterator(
- const FilePath::StringType& executable_name,
- const ProcessFilter* filter) : ProcessIterator(filter),
- executable_name_(executable_name) {
-#if defined(OS_ANDROID)
- // On Android, the process name contains only the last 15 characters, which
- // is in file /proc/<pid>/stat, the string between open parenthesis and close
- // parenthesis. Please See ProcessIterator::CheckForNextProcess for details.
- // Now if the length of input process name is greater than 15, only save the
- // last 15 characters.
- if (executable_name_.size() > 15) {
- executable_name_ = FilePath::StringType(executable_name_,
- executable_name_.size() - 15, 15);
- }
-#endif
-}
-
-NamedProcessIterator::~NamedProcessIterator() {
-}
-
} // namespace base
diff --git a/base/process_util.h b/base/process_util.h
index 2036ca8..0bec8e0 100644
--- a/base/process_util.h
+++ b/base/process_util.h
@@ -15,9 +15,6 @@
#include <windows.h>
#include <tlhelp32.h>
#elif defined(OS_MACOSX) || defined(OS_BSD)
-// kinfo_proc is defined in <sys/sysctl.h>, but this forward declaration
-// is sufficient for the vector<kinfo_proc> below.
-struct kinfo_proc;
// malloc_zone_t is defined in <malloc/malloc.h>, but this forward declaration
// is sufficient for GetPurgeableZone() below.
typedef struct _malloc_zone_t malloc_zone_t;
@@ -39,6 +36,7 @@ typedef struct _malloc_zone_t malloc_zone_t;
#include "base/base_export.h"
#include "base/files/file_path.h"
#include "base/process.h"
+#include "base/process/process_iterator.h"
#include "base/process/process_metrics.h"
#if defined(OS_POSIX)
@@ -49,71 +47,6 @@ class CommandLine;
namespace base {
-#if defined(OS_WIN)
-struct ProcessEntry : public PROCESSENTRY32 {
- ProcessId pid() const { return th32ProcessID; }
- ProcessId parent_pid() const { return th32ParentProcessID; }
- const wchar_t* exe_file() const { return szExeFile; }
-};
-
-// Process access masks. These constants provide platform-independent
-// definitions for the standard Windows access masks.
-// See http://msdn.microsoft.com/en-us/library/ms684880(VS.85).aspx for
-// the specific semantics of each mask value.
-const uint32 kProcessAccessTerminate = PROCESS_TERMINATE;
-const uint32 kProcessAccessCreateThread = PROCESS_CREATE_THREAD;
-const uint32 kProcessAccessSetSessionId = PROCESS_SET_SESSIONID;
-const uint32 kProcessAccessVMOperation = PROCESS_VM_OPERATION;
-const uint32 kProcessAccessVMRead = PROCESS_VM_READ;
-const uint32 kProcessAccessVMWrite = PROCESS_VM_WRITE;
-const uint32 kProcessAccessDuplicateHandle = PROCESS_DUP_HANDLE;
-const uint32 kProcessAccessCreateProcess = PROCESS_CREATE_PROCESS;
-const uint32 kProcessAccessSetQuota = PROCESS_SET_QUOTA;
-const uint32 kProcessAccessSetInformation = PROCESS_SET_INFORMATION;
-const uint32 kProcessAccessQueryInformation = PROCESS_QUERY_INFORMATION;
-const uint32 kProcessAccessSuspendResume = PROCESS_SUSPEND_RESUME;
-const uint32 kProcessAccessQueryLimitedInfomation =
- PROCESS_QUERY_LIMITED_INFORMATION;
-const uint32 kProcessAccessWaitForTermination = SYNCHRONIZE;
-#elif defined(OS_POSIX)
-
-struct BASE_EXPORT ProcessEntry {
- ProcessEntry();
- ~ProcessEntry();
-
- ProcessId pid() const { return pid_; }
- ProcessId parent_pid() const { return ppid_; }
- ProcessId gid() const { return gid_; }
- const char* exe_file() const { return exe_file_.c_str(); }
- const std::vector<std::string>& cmd_line_args() const {
- return cmd_line_args_;
- }
-
- ProcessId pid_;
- ProcessId ppid_;
- ProcessId gid_;
- std::string exe_file_;
- std::vector<std::string> cmd_line_args_;
-};
-
-// Process access masks. They are not used on Posix because access checking
-// does not happen during handle creation.
-const uint32 kProcessAccessTerminate = 0;
-const uint32 kProcessAccessCreateThread = 0;
-const uint32 kProcessAccessSetSessionId = 0;
-const uint32 kProcessAccessVMOperation = 0;
-const uint32 kProcessAccessVMRead = 0;
-const uint32 kProcessAccessVMWrite = 0;
-const uint32 kProcessAccessDuplicateHandle = 0;
-const uint32 kProcessAccessCreateProcess = 0;
-const uint32 kProcessAccessSetQuota = 0;
-const uint32 kProcessAccessSetInformation = 0;
-const uint32 kProcessAccessQueryInformation = 0;
-const uint32 kProcessAccessSuspendResume = 0;
-const uint32 kProcessAccessQueryLimitedInfomation = 0;
-const uint32 kProcessAccessWaitForTermination = 0;
-#endif // defined(OS_POSIX)
-
// Return status values from GetTerminationStatus. Don't use these as
// exit code arguments to KillProcess*(), use platform/application
// specific values instead.
@@ -433,23 +366,6 @@ BASE_EXPORT bool GetAppOutputWithExitCode(const CommandLine& cl,
std::string* output, int* exit_code);
#endif // defined(OS_POSIX)
-// Used to filter processes by process ID.
-class ProcessFilter {
- public:
- // Returns true to indicate set-inclusion and false otherwise. This method
- // should not have side-effects and should be idempotent.
- virtual bool Includes(const ProcessEntry& entry) const = 0;
-
- protected:
- virtual ~ProcessFilter() {}
-};
-
-// Returns the number of processes on the machine that are running from the
-// given executable name. If filter is non-null, then only processes selected
-// by the filter will be counted.
-BASE_EXPORT int GetProcessCount(const FilePath::StringType& executable_name,
- const ProcessFilter* filter);
-
// Attempts to kill all the processes on the current machine that were launched
// from the given executable name, ending them with the given exit code. If
// filter is non-null, then only processes selected by the filter are killed.
@@ -559,75 +475,6 @@ BASE_EXPORT void EnsureProcessTerminated(ProcessHandle process_handle);
BASE_EXPORT void EnsureProcessGetsReaped(ProcessHandle process_handle);
#endif
-// This class provides a way to iterate through a list of processes on the
-// current machine with a specified filter.
-// To use, create an instance and then call NextProcessEntry() until it returns
-// false.
-class BASE_EXPORT ProcessIterator {
- public:
- typedef std::list<ProcessEntry> ProcessEntries;
-
- explicit ProcessIterator(const ProcessFilter* filter);
- virtual ~ProcessIterator();
-
- // If there's another process that matches the given executable name,
- // returns a const pointer to the corresponding PROCESSENTRY32.
- // If there are no more matching processes, returns NULL.
- // The returned pointer will remain valid until NextProcessEntry()
- // is called again or this NamedProcessIterator goes out of scope.
- const ProcessEntry* NextProcessEntry();
-
- // Takes a snapshot of all the ProcessEntry found.
- ProcessEntries Snapshot();
-
- protected:
- virtual bool IncludeEntry();
- const ProcessEntry& entry() { return entry_; }
-
- private:
- // Determines whether there's another process (regardless of executable)
- // left in the list of all processes. Returns true and sets entry_ to
- // that process's info if there is one, false otherwise.
- bool CheckForNextProcess();
-
- // Initializes a PROCESSENTRY32 data structure so that it's ready for
- // use with Process32First/Process32Next.
- void InitProcessEntry(ProcessEntry* entry);
-
-#if defined(OS_WIN)
- HANDLE snapshot_;
- bool started_iteration_;
-#elif defined(OS_MACOSX) || defined(OS_BSD)
- std::vector<kinfo_proc> kinfo_procs_;
- size_t index_of_kinfo_proc_;
-#elif defined(OS_POSIX)
- DIR* procfs_dir_;
-#endif
- ProcessEntry entry_;
- const ProcessFilter* filter_;
-
- DISALLOW_COPY_AND_ASSIGN(ProcessIterator);
-};
-
-// This class provides a way to iterate through the list of processes
-// on the current machine that were started from the given executable
-// name. To use, create an instance and then call NextProcessEntry()
-// until it returns false.
-class BASE_EXPORT NamedProcessIterator : public ProcessIterator {
- public:
- NamedProcessIterator(const FilePath::StringType& executable_name,
- const ProcessFilter* filter);
- virtual ~NamedProcessIterator();
-
- protected:
- virtual bool IncludeEntry() OVERRIDE;
-
- private:
- FilePath::StringType executable_name_;
-
- DISALLOW_COPY_AND_ASSIGN(NamedProcessIterator);
-};
-
// Enables low fragmentation heap (LFH) for every heaps of this process. This
// won't have any effect on heaps created after this function call. It will not
// modify data allocated in the heaps before calling this function. So it is
diff --git a/base/process_util_freebsd.cc b/base/process_util_freebsd.cc
index bcf629f..4ea934a 100644
--- a/base/process_util_freebsd.cc
+++ b/base/process_util_freebsd.cc
@@ -52,116 +52,6 @@ FilePath GetProcessExecutablePath(ProcessHandle process) {
return FilePath(std::string(pathname));
}
-ProcessIterator::ProcessIterator(const ProcessFilter* filter)
- : index_of_kinfo_proc_(),
- filter_(filter) {
-
- int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, getuid() };
-
- bool done = false;
- int try_num = 1;
- const int max_tries = 10;
-
- do {
- size_t len = 0;
- if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) {
- LOG(ERROR) << "failed to get the size needed for the process list";
- kinfo_procs_.resize(0);
- done = true;
- } else {
- size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
- // Leave some spare room for process table growth (more could show up
- // between when we check and now)
- num_of_kinfo_proc += 16;
- kinfo_procs_.resize(num_of_kinfo_proc);
- len = num_of_kinfo_proc * sizeof(struct kinfo_proc);
- if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) <0) {
- // If we get a mem error, it just means we need a bigger buffer, so
- // loop around again. Anything else is a real error and give up.
- if (errno != ENOMEM) {
- LOG(ERROR) << "failed to get the process list";
- kinfo_procs_.resize(0);
- done = true;
- }
- } else {
- // Got the list, just make sure we're sized exactly right
- size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
- kinfo_procs_.resize(num_of_kinfo_proc);
- done = true;
- }
- }
- } while (!done && (try_num++ < max_tries));
-
- if (!done) {
- LOG(ERROR) << "failed to collect the process list in a few tries";
- kinfo_procs_.resize(0);
- }
-}
-
-ProcessIterator::~ProcessIterator() {
-}
-
-bool ProcessIterator::CheckForNextProcess() {
- std::string data;
-
- for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
- size_t length;
- struct kinfo_proc kinfo = kinfo_procs_[index_of_kinfo_proc_];
- int mib[] = { CTL_KERN, KERN_PROC_ARGS, kinfo.ki_pid };
-
- if ((kinfo.ki_pid > 0) && (kinfo.ki_stat == SZOMB))
- continue;
-
- length = 0;
- if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0) {
- LOG(ERROR) << "failed to figure out the buffer size for a command line";
- continue;
- }
-
- data.resize(length);
-
- if (sysctl(mib, arraysize(mib), &data[0], &length, NULL, 0) < 0) {
- LOG(ERROR) << "failed to fetch a commandline";
- continue;
- }
-
- std::string delimiters;
- delimiters.push_back('\0');
- Tokenize(data, delimiters, &entry_.cmd_line_args_);
-
- size_t exec_name_end = data.find('\0');
- if (exec_name_end == std::string::npos) {
- LOG(ERROR) << "command line data didn't match expected format";
- continue;
- }
-
- entry_.pid_ = kinfo.ki_pid;
- entry_.ppid_ = kinfo.ki_ppid;
- entry_.gid_ = kinfo.ki_pgid;
-
- size_t last_slash = data.rfind('/', exec_name_end);
- if (last_slash == std::string::npos) {
- entry_.exe_file_.assign(data, 0, exec_name_end);
- } else {
- entry_.exe_file_.assign(data, last_slash + 1,
- exec_name_end - last_slash - 1);
- }
-
- // Start w/ the next entry next time through
- ++index_of_kinfo_proc_;
-
- return true;
- }
- return false;
-}
-
-bool NamedProcessIterator::IncludeEntry() {
- if (executable_name_ != entry().exe_file())
- return false;
-
- return ProcessIterator::IncludeEntry();
-}
-
void EnableTerminationOnOutOfMemory() {
DLOG(WARNING) << "Not feasible.";
}
diff --git a/base/process_util_linux.cc b/base/process_util_linux.cc
index 4f510d7..32f191e 100644
--- a/base/process_util_linux.cc
+++ b/base/process_util_linux.cc
@@ -21,48 +21,6 @@
namespace base {
-namespace {
-
-// Reads the |field_num|th field from |proc_stats|.
-// Returns an empty string on failure.
-// This version only handles VM_COMM and VM_STATE, which are the only fields
-// that are strings.
-std::string GetProcStatsFieldAsString(
- const std::vector<std::string>& proc_stats,
- internal::ProcStatsFields field_num) {
- if (field_num < internal::VM_COMM || field_num > internal::VM_STATE) {
- NOTREACHED();
- return std::string();
- }
-
- if (proc_stats.size() > static_cast<size_t>(field_num))
- return proc_stats[field_num];
-
- NOTREACHED();
- return 0;
-}
-
-// Reads /proc/<pid>/cmdline and populates |proc_cmd_line_args| with the command
-// line arguments. Returns true if successful.
-// Note: /proc/<pid>/cmdline contains command line arguments separated by single
-// null characters. We tokenize it into a vector of strings using '\0' as a
-// delimiter.
-bool GetProcCmdline(pid_t pid, std::vector<std::string>* proc_cmd_line_args) {
- // Synchronously reading files in /proc is safe.
- ThreadRestrictions::ScopedAllowIO allow_io;
-
- FilePath cmd_line_file = internal::GetProcPidDir(pid).Append("cmdline");
- std::string cmd_line;
- if (!file_util::ReadFileToString(cmd_line_file, &cmd_line))
- return false;
- std::string delimiters;
- delimiters.push_back('\0');
- Tokenize(cmd_line, delimiters, proc_cmd_line_args);
- return true;
-}
-
-} // namespace
-
#if defined(USE_LINUX_BREAKPAD)
size_t g_oom_size = 0U;
#endif
@@ -87,87 +45,6 @@ FilePath GetProcessExecutablePath(ProcessHandle process) {
return exe_name;
}
-ProcessIterator::ProcessIterator(const ProcessFilter* filter)
- : filter_(filter) {
- procfs_dir_ = opendir(internal::kProcDir);
-}
-
-ProcessIterator::~ProcessIterator() {
- if (procfs_dir_) {
- closedir(procfs_dir_);
- procfs_dir_ = NULL;
- }
-}
-
-bool ProcessIterator::CheckForNextProcess() {
- // TODO(port): skip processes owned by different UID
-
- pid_t pid = kNullProcessId;
- std::vector<std::string> cmd_line_args;
- std::string stats_data;
- std::vector<std::string> proc_stats;
-
- // Arbitrarily guess that there will never be more than 200 non-process
- // files in /proc. Hardy has 53 and Lucid has 61.
- int skipped = 0;
- const int kSkipLimit = 200;
- while (skipped < kSkipLimit) {
- dirent* slot = readdir(procfs_dir_);
- // all done looking through /proc?
- if (!slot)
- return false;
-
- // If not a process, keep looking for one.
- pid = internal::ProcDirSlotToPid(slot->d_name);
- if (!pid) {
- skipped++;
- continue;
- }
-
- if (!GetProcCmdline(pid, &cmd_line_args))
- continue;
-
- if (!internal::ReadProcStats(pid, &stats_data))
- continue;
- if (!internal::ParseProcStats(stats_data, &proc_stats))
- continue;
-
- std::string runstate =
- GetProcStatsFieldAsString(proc_stats, internal::VM_STATE);
- if (runstate.size() != 1) {
- NOTREACHED();
- continue;
- }
-
- // Is the process in 'Zombie' state, i.e. dead but waiting to be reaped?
- // Allowed values: D R S T Z
- if (runstate[0] != 'Z')
- break;
-
- // Nope, it's a zombie; somebody isn't cleaning up after their children.
- // (e.g. WaitForProcessesToExit doesn't clean up after dead children yet.)
- // There could be a lot of zombies, can't really decrement i here.
- }
- if (skipped >= kSkipLimit) {
- NOTREACHED();
- return false;
- }
-
- entry_.pid_ = pid;
- entry_.ppid_ = GetProcStatsFieldAsInt(proc_stats, internal::VM_PPID);
- entry_.gid_ = GetProcStatsFieldAsInt(proc_stats, internal::VM_PGRP);
- entry_.cmd_line_args_.assign(cmd_line_args.begin(), cmd_line_args.end());
- entry_.exe_file_ = GetProcessExecutablePath(pid).BaseName().value();
- return true;
-}
-
-bool NamedProcessIterator::IncludeEntry() {
- if (executable_name_ != entry().exe_file())
- return false;
- return ProcessIterator::IncludeEntry();
-}
-
-
int GetNumberOfThreads(ProcessHandle process) {
return internal::ReadProcStatsAndGetFieldAsInt(process,
internal::VM_NUMTHREADS);
diff --git a/base/process_util_mac.mm b/base/process_util_mac.mm
index c9f0ef7..83a24b8 100644
--- a/base/process_util_mac.mm
+++ b/base/process_util_mac.mm
@@ -65,123 +65,6 @@ void RestoreDefaultExceptionHandler() {
EXCEPTION_DEFAULT, THREAD_STATE_NONE);
}
-ProcessIterator::ProcessIterator(const ProcessFilter* filter)
- : index_of_kinfo_proc_(0),
- filter_(filter) {
- // Get a snapshot of all of my processes (yes, as we loop it can go stale, but
- // but trying to find where we were in a constantly changing list is basically
- // impossible.
-
- int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, geteuid() };
-
- // Since more processes could start between when we get the size and when
- // we get the list, we do a loop to keep trying until we get it.
- bool done = false;
- int try_num = 1;
- const int max_tries = 10;
- do {
- // Get the size of the buffer
- size_t len = 0;
- if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) {
- DLOG(ERROR) << "failed to get the size needed for the process list";
- kinfo_procs_.resize(0);
- done = true;
- } else {
- size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
- // Leave some spare room for process table growth (more could show up
- // between when we check and now)
- num_of_kinfo_proc += 16;
- kinfo_procs_.resize(num_of_kinfo_proc);
- len = num_of_kinfo_proc * sizeof(struct kinfo_proc);
- // Load the list of processes
- if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) < 0) {
- // If we get a mem error, it just means we need a bigger buffer, so
- // loop around again. Anything else is a real error and give up.
- if (errno != ENOMEM) {
- DLOG(ERROR) << "failed to get the process list";
- kinfo_procs_.resize(0);
- done = true;
- }
- } else {
- // Got the list, just make sure we're sized exactly right
- size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
- kinfo_procs_.resize(num_of_kinfo_proc);
- done = true;
- }
- }
- } while (!done && (try_num++ < max_tries));
-
- if (!done) {
- DLOG(ERROR) << "failed to collect the process list in a few tries";
- kinfo_procs_.resize(0);
- }
-}
-
-ProcessIterator::~ProcessIterator() {
-}
-
-bool ProcessIterator::CheckForNextProcess() {
- std::string data;
- for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
- kinfo_proc& kinfo = kinfo_procs_[index_of_kinfo_proc_];
-
- // Skip processes just awaiting collection
- if ((kinfo.kp_proc.p_pid > 0) && (kinfo.kp_proc.p_stat == SZOMB))
- continue;
-
- int mib[] = { CTL_KERN, KERN_PROCARGS, kinfo.kp_proc.p_pid };
-
- // Find out what size buffer we need.
- size_t data_len = 0;
- if (sysctl(mib, arraysize(mib), NULL, &data_len, NULL, 0) < 0) {
- DVPLOG(1) << "failed to figure out the buffer size for a commandline";
- continue;
- }
-
- data.resize(data_len);
- if (sysctl(mib, arraysize(mib), &data[0], &data_len, NULL, 0) < 0) {
- DVPLOG(1) << "failed to fetch a commandline";
- continue;
- }
-
- // |data| contains all the command line parameters of the process, separated
- // by blocks of one or more null characters. We tokenize |data| into a
- // vector of strings using '\0' as a delimiter and populate
- // |entry_.cmd_line_args_|.
- std::string delimiters;
- delimiters.push_back('\0');
- Tokenize(data, delimiters, &entry_.cmd_line_args_);
-
- // |data| starts with the full executable path followed by a null character.
- // We search for the first instance of '\0' and extract everything before it
- // to populate |entry_.exe_file_|.
- size_t exec_name_end = data.find('\0');
- if (exec_name_end == std::string::npos) {
- DLOG(ERROR) << "command line data didn't match expected format";
- continue;
- }
-
- entry_.pid_ = kinfo.kp_proc.p_pid;
- entry_.ppid_ = kinfo.kp_eproc.e_ppid;
- entry_.gid_ = kinfo.kp_eproc.e_pgid;
- size_t last_slash = data.rfind('/', exec_name_end);
- if (last_slash == std::string::npos)
- entry_.exe_file_.assign(data, 0, exec_name_end);
- else
- entry_.exe_file_.assign(data, last_slash + 1,
- exec_name_end - last_slash - 1);
- // Start w/ the next entry next time through
- ++index_of_kinfo_proc_;
- // Done
- return true;
- }
- return false;
-}
-
-bool NamedProcessIterator::IncludeEntry() {
- return (executable_name_ == entry().exe_file() &&
- ProcessIterator::IncludeEntry());
-}
// These are helpers for EnableTerminationOnHeapCorruption, which is a no-op
diff --git a/base/process_util_openbsd.cc b/base/process_util_openbsd.cc
index de16909..5179786 100644
--- a/base/process_util_openbsd.cc
+++ b/base/process_util_openbsd.cc
@@ -64,120 +64,6 @@ FilePath GetProcessExecutablePath(ProcessHandle process) {
return FilePath();
}
-ProcessIterator::ProcessIterator(const ProcessFilter* filter)
- : index_of_kinfo_proc_(),
- filter_(filter) {
-
- int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, getuid(),
- sizeof(struct kinfo_proc), 0 };
-
- bool done = false;
- int try_num = 1;
- const int max_tries = 10;
-
- do {
- size_t len = 0;
- if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) {
- DLOG(ERROR) << "failed to get the size needed for the process list";
- kinfo_procs_.resize(0);
- done = true;
- } else {
- size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
- // Leave some spare room for process table growth (more could show up
- // between when we check and now)
- num_of_kinfo_proc += 16;
- kinfo_procs_.resize(num_of_kinfo_proc);
- len = num_of_kinfo_proc * sizeof(struct kinfo_proc);
- if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) < 0) {
- // If we get a mem error, it just means we need a bigger buffer, so
- // loop around again. Anything else is a real error and give up.
- if (errno != ENOMEM) {
- DLOG(ERROR) << "failed to get the process list";
- kinfo_procs_.resize(0);
- done = true;
- }
- } else {
- // Got the list, just make sure we're sized exactly right
- size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
- kinfo_procs_.resize(num_of_kinfo_proc);
- done = true;
- }
- }
- } while (!done && (try_num++ < max_tries));
-
- if (!done) {
- DLOG(ERROR) << "failed to collect the process list in a few tries";
- kinfo_procs_.resize(0);
- }
-}
-
-ProcessIterator::~ProcessIterator() {
-}
-
-bool ProcessIterator::CheckForNextProcess() {
- std::string data;
- for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
- kinfo_proc& kinfo = kinfo_procs_[index_of_kinfo_proc_];
-
- // Skip processes just awaiting collection
- if ((kinfo.p_pid > 0) && (kinfo.p_stat == SZOMB))
- continue;
-
- int mib[] = { CTL_KERN, KERN_PROC_ARGS, kinfo.p_pid };
-
- // Find out what size buffer we need.
- size_t data_len = 0;
- if (sysctl(mib, arraysize(mib), NULL, &data_len, NULL, 0) < 0) {
- DVPLOG(1) << "failed to figure out the buffer size for a commandline";
- continue;
- }
-
- data.resize(data_len);
- if (sysctl(mib, arraysize(mib), &data[0], &data_len, NULL, 0) < 0) {
- DVPLOG(1) << "failed to fetch a commandline";
- continue;
- }
-
- // |data| contains all the command line parameters of the process, separated
- // by blocks of one or more null characters. We tokenize |data| into a
- // vector of strings using '\0' as a delimiter and populate
- // |entry_.cmd_line_args_|.
- std::string delimiters;
- delimiters.push_back('\0');
- Tokenize(data, delimiters, &entry_.cmd_line_args_);
-
- // |data| starts with the full executable path followed by a null character.
- // We search for the first instance of '\0' and extract everything before it
- // to populate |entry_.exe_file_|.
- size_t exec_name_end = data.find('\0');
- if (exec_name_end == std::string::npos) {
- DLOG(ERROR) << "command line data didn't match expected format";
- continue;
- }
-
- entry_.pid_ = kinfo.p_pid;
- entry_.ppid_ = kinfo.p_ppid;
- entry_.gid_ = kinfo.p__pgid;
- size_t last_slash = data.rfind('/', exec_name_end);
- if (last_slash == std::string::npos)
- entry_.exe_file_.assign(data, 0, exec_name_end);
- else
- entry_.exe_file_.assign(data, last_slash + 1,
- exec_name_end - last_slash - 1);
- // Start w/ the next entry next time through
- ++index_of_kinfo_proc_;
- // Done
- return true;
- }
- return false;
-}
-
-bool NamedProcessIterator::IncludeEntry() {
- return (executable_name_ == entry().exe_file() &&
- ProcessIterator::IncludeEntry());
-}
-
-
void EnableTerminationOnOutOfMemory() {
}
diff --git a/base/process_util_win.cc b/base/process_util_win.cc
index 1a30d0e..7119004 100644
--- a/base/process_util_win.cc
+++ b/base/process_util_win.cc
@@ -589,38 +589,6 @@ bool WaitForExitCodeWithTimeout(ProcessHandle handle, int* exit_code,
return true;
}
-ProcessIterator::ProcessIterator(const ProcessFilter* filter)
- : started_iteration_(false),
- filter_(filter) {
- snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
-}
-
-ProcessIterator::~ProcessIterator() {
- CloseHandle(snapshot_);
-}
-
-bool ProcessIterator::CheckForNextProcess() {
- InitProcessEntry(&entry_);
-
- if (!started_iteration_) {
- started_iteration_ = true;
- return !!Process32First(snapshot_, &entry_);
- }
-
- return !!Process32Next(snapshot_, &entry_);
-}
-
-void ProcessIterator::InitProcessEntry(ProcessEntry* entry) {
- memset(entry, 0, sizeof(*entry));
- entry->dwSize = sizeof(*entry);
-}
-
-bool NamedProcessIterator::IncludeEntry() {
- // Case insensitive.
- return _wcsicmp(executable_name_.c_str(), entry().exe_file()) == 0 &&
- ProcessIterator::IncludeEntry();
-}
-
bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
base::TimeDelta wait,
const ProcessFilter* filter) {