diff options
author | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-31 15:38:01 +0000 |
---|---|---|
committer | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-31 15:38:01 +0000 |
commit | d3acb67574294e4e0b3b74840558ef81ebb433b5 (patch) | |
tree | 84472dcdaf777dfdecd1644e2256bd985d791f3d /base/process/process_iterator_linux.cc | |
parent | 52325b2a52aa5ea3adab9edbab67a10380c08618 (diff) | |
download | chromium_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.cc | 138 |
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 |