summaryrefslogtreecommitdiffstats
path: root/base/process/process_iterator_linux.cc
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/process/process_iterator_linux.cc
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/process/process_iterator_linux.cc')
-rw-r--r--base/process/process_iterator_linux.cc138
1 files changed, 138 insertions, 0 deletions
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