Commit b6128aab authored by maruel@chromium.org's avatar maruel@chromium.org

Move common code into process_util.cc.

Fix namespace usage.
Change ProcessEntry to have a common interface accross platforms and change ProcessFilter::Includes() to make use of it.
Split NamedProcessIterator in two.

BUG=none
TEST=none

Review URL: http://codereview.chromium.org/1689012

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@45953 0039d316-1c4b-4281-b951-d872f2087c98
parent a65b0ba0
......@@ -154,6 +154,7 @@
'process.h',
'process_linux.cc',
'process_posix.cc',
'process_util.cc',
'process_util.h',
'process_util_linux.cc',
'process_util_mac.mm',
......
......@@ -9,7 +9,7 @@
#include "build/build_config.h"
#include <sys/types.h>
#ifdef OS_WIN
#if defined(OS_WIN)
#include <windows.h>
#endif
......@@ -28,7 +28,7 @@ const ProcessHandle kNullProcessHandle = NULL;
typedef pid_t ProcessHandle;
typedef pid_t ProcessId;
const ProcessHandle kNullProcessHandle = 0;
#endif
#endif // defined(OS_WIN)
#if defined(OS_POSIX) && !defined(OS_MACOSX)
// saved_priority_ will be set to this to indicate that it's not holding
......
// Copyright (c) 2010 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_util.h"
namespace base {
int GetProcessCount(const std::wstring& executable_name,
const ProcessFilter* filter) {
int count = 0;
NamedProcessIterator iter(executable_name, filter);
while (iter.NextProcessEntry())
++count;
return count;
}
bool KillProcesses(const std::wstring& executable_name, int exit_code,
const ProcessFilter* filter) {
bool result = true;
NamedProcessIterator iter(executable_name, filter);
while (const ProcessEntry* entry = iter.NextProcessEntry()) {
#if defined(OS_WIN)
result &= KillProcessById(entry->pid(), exit_code, true);
#else
result &= KillProcess(entry->pid(), exit_code, true);
#endif
}
return result;
}
const ProcessEntry* ProcessIterator::NextProcessEntry() {
bool result = false;
do {
result = CheckForNextProcess();
} while (result && !IncludeEntry());
if (result)
return &entry_;
return NULL;
}
bool ProcessIterator::IncludeEntry() {
return !filter_ || filter_->Includes(entry_);
}
std::list<ProcessEntry> ProcessIterator::Snapshot() {
std::list<ProcessEntry> found;
while (const ProcessEntry* process_entry = NextProcessEntry()) {
found.push_back(*process_entry);
}
return found;
}
NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name,
const ProcessFilter* filter)
: ProcessIterator(filter),
executable_name_(executable_name) {
}
NamedProcessIterator::~NamedProcessIterator() {
}
} // namespace base
......@@ -24,6 +24,7 @@ struct kinfo_proc;
#include <sys/types.h>
#endif
#include <list>
#include <string>
#include <utility>
#include <vector>
......@@ -46,16 +47,25 @@ 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; }
};
struct IoCounters : public IO_COUNTERS {
};
#elif defined(OS_POSIX)
struct ProcessEntry {
base::ProcessId pid;
base::ProcessId ppid;
char szExeFile[NAME_MAX + 1];
ProcessId pid_;
ProcessId ppid_;
ProcessId gid_;
std::string exe_file_;
ProcessId pid() const { return pid_; }
ProcessId parent_pid() const { return ppid_; }
const char* exe_file() const { return exe_file_.c_str(); }
};
struct IoCounters {
......@@ -126,7 +136,7 @@ bool AdjustOOMScore(ProcessId process, int score);
// Close all file descriptors, expect those which are a destination in the
// given multimap. Only call this function in a child process where you know
// that there aren't any other threads.
void CloseSuperfluousFds(const base::InjectiveMultimap& saved_map);
void CloseSuperfluousFds(const InjectiveMultimap& saved_map);
#endif
#if defined(OS_WIN)
......@@ -239,7 +249,7 @@ 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(ProcessId pid, ProcessId parent_pid) const = 0;
virtual bool Includes(const ProcessEntry& entry) const = 0;
};
// Returns the number of processes on the machine that are running from the
......@@ -312,15 +322,14 @@ bool CleanupProcesses(const std::wstring& executable_name,
int exit_code,
const ProcessFilter* filter);
// 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 NamedProcessIterator {
// 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 ProcessIterator {
public:
NamedProcessIterator(const std::wstring& executable_name,
const ProcessFilter* filter);
~NamedProcessIterator();
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.
......@@ -329,20 +338,23 @@ class NamedProcessIterator {
// is called again or this NamedProcessIterator goes out of scope.
const ProcessEntry* NextProcessEntry();
// Takes a snapshot of all the ProcessEntry found.
std::list<ProcessEntry> 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();
bool IncludeEntry();
// Initializes a PROCESSENTRY32 data structure so that it's ready for
// use with Process32First/Process32Next.
void InitProcessEntry(ProcessEntry* entry);
std::wstring executable_name_;
#if defined(OS_WIN)
HANDLE snapshot_;
bool started_iteration_;
......@@ -355,7 +367,26 @@ class NamedProcessIterator {
ProcessEntry entry_;
const ProcessFilter* filter_;
DISALLOW_EVIL_CONSTRUCTORS(NamedProcessIterator);
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 NamedProcessIterator : public ProcessIterator {
public:
NamedProcessIterator(const std::wstring& executable_name,
const ProcessFilter* filter);
virtual ~NamedProcessIterator();
protected:
virtual bool IncludeEntry();
private:
std::wstring executable_name_;
DISALLOW_COPY_AND_ASSIGN(NamedProcessIterator);
};
// Working Set (resident) memory usage broken down by
......@@ -435,7 +466,7 @@ class ProcessMetrics {
// only returns valid metrics if |process| is the current process.
static ProcessMetrics* CreateProcessMetrics(ProcessHandle process,
PortProvider* port_provider);
#endif
#endif // !defined(OS_MACOSX)
~ProcessMetrics();
......@@ -487,7 +518,7 @@ class ProcessMetrics {
explicit ProcessMetrics(ProcessHandle process);
#else
ProcessMetrics(ProcessHandle process, PortProvider* port_provider);
#endif
#endif // !defined(OS_MACOSX)
ProcessHandle process_;
......@@ -506,9 +537,9 @@ class ProcessMetrics {
#elif defined(OS_POSIX)
// Jiffie count at the last_time_ we updated.
int last_cpu_;
#endif
#endif // defined(OS_MACOSX)
DISALLOW_EVIL_CONSTRUCTORS(ProcessMetrics);
DISALLOW_COPY_AND_ASSIGN(ProcessMetrics);
};
// Returns the memory commited by the system in KBytes.
......@@ -553,7 +584,7 @@ void RaiseProcessToHighPriority();
// in the child after forking will restore the standard exception handler.
// See http://crbug.com/20371/ for more details.
void RestoreDefaultExceptionHandler();
#endif
#endif // defined(OS_MACOSX)
} // namespace base
......
......@@ -19,6 +19,7 @@
#include "base/logging.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "base/sys_info.h"
namespace {
......@@ -87,32 +88,19 @@ FilePath GetProcessExecutablePath(ProcessHandle process) {
return FilePath(std::string(exename, len));
}
NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name,
const ProcessFilter* filter)
: executable_name_(executable_name), filter_(filter) {
ProcessIterator::ProcessIterator(const ProcessFilter* filter)
: filter_(filter) {
procfs_dir_ = opendir("/proc");
}
NamedProcessIterator::~NamedProcessIterator() {
ProcessIterator::~ProcessIterator() {
if (procfs_dir_) {
closedir(procfs_dir_);
procfs_dir_ = NULL;
}
}
const ProcessEntry* NamedProcessIterator::NextProcessEntry() {
bool result = false;
do {
result = CheckForNextProcess();
} while (result && !IncludeEntry());
if (result)
return &entry_;
return NULL;
}
bool NamedProcessIterator::CheckForNextProcess() {
bool ProcessIterator::CheckForNextProcess() {
// TODO(port): skip processes owned by different UID
dirent* slot = 0;
......@@ -155,8 +143,8 @@ bool NamedProcessIterator::CheckForNextProcess() {
return false;
// Parse the status. It is formatted like this:
// %d (%s) %c %d ...
// pid (name) runstate ppid
// %d (%s) %c %d %d ...
// pid (name) runstate ppid gid
// To avoid being fooled by names containing a closing paren, scan
// backwards.
openparen = strchr(buf, '(');
......@@ -179,27 +167,37 @@ bool NamedProcessIterator::CheckForNextProcess() {
return false;
}
entry_.pid = atoi(slot->d_name);
entry_.ppid = atoi(closeparen + 3);
// This seems fragile.
entry_.pid_ = atoi(slot->d_name);
entry_.ppid_ = atoi(closeparen + 3);
entry_.gid_ = atoi(strchr(closeparen + 4, ' '));
// TODO(port): read pid's commandline's $0, like killall does. Using the
// short name between openparen and closeparen won't work for long names!
int len = closeparen - openparen - 1;
if (len > NAME_MAX)
len = NAME_MAX;
memcpy(entry_.szExeFile, openparen + 1, len);
entry_.szExeFile[len] = 0;
entry_.exe_file_.assign(openparen + 1, len);
return true;
}
bool NamedProcessIterator::IncludeEntry() {
// TODO(port): make this also work for non-ASCII filenames
if (WideToASCII(executable_name_) != entry_.szExeFile)
if (WideToASCII(executable_name_) != entry().exe_file())
return false;
if (!filter_)
return true;
return filter_->Includes(entry_.pid, entry_.ppid);
return ProcessIterator::IncludeEntry();
}
ProcessMetrics::ProcessMetrics(ProcessHandle process)
: process_(process),
last_time_(0),
last_system_time_(0),
last_cpu_(0) {
processor_count_ = base::SysInfo::NumberOfProcessors();
}
// static
ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
return new ProcessMetrics(process);
}
// On linux, we return vsize.
......
......@@ -48,10 +48,8 @@ void RestoreDefaultExceptionHandler() {
EXCEPTION_DEFAULT, THREAD_STATE_NONE);
}
NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name,
const ProcessFilter* filter)
: executable_name_(executable_name),
index_of_kinfo_proc_(0),
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
......@@ -75,7 +73,7 @@ NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name,
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 += 4;
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
......@@ -102,38 +100,21 @@ NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name,
}
}
NamedProcessIterator::~NamedProcessIterator() {
ProcessIterator::~ProcessIterator() {
}
const ProcessEntry* NamedProcessIterator::NextProcessEntry() {
bool result = false;
do {
result = CheckForNextProcess();
} while (result && !IncludeEntry());
if (result) {
return &entry_;
}
return NULL;
}
bool NamedProcessIterator::CheckForNextProcess() {
std::string executable_name_utf8(base::SysWideToUTF8(executable_name_));
bool ProcessIterator::CheckForNextProcess() {
std::string data;
std::string exec_name;
for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
kinfo_proc* kinfo = &kinfo_procs_[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))
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 };
int mib[] = { CTL_KERN, KERN_PROCARGS, kinfo.kp_proc.p_pid };
// Found out what size buffer we need
// Find out what size buffer we need.
size_t data_len = 0;
if (sysctl(mib, arraysize(mib), NULL, &data_len, NULL, 0) < 0) {
LOG(ERROR) << "failed to figure out the buffer size for a commandline";
......@@ -154,32 +135,26 @@ bool NamedProcessIterator::CheckForNextProcess() {
LOG(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)
exec_name = data.substr(0, exec_name_end);
entry_.exe_file_.assign(data, 0, exec_name_end);
else
exec_name = data.substr(last_slash + 1, exec_name_end - last_slash - 1);
// Check the name
if (executable_name_utf8 == exec_name) {
entry_.pid = kinfo->kp_proc.p_pid;
entry_.ppid = kinfo->kp_eproc.e_ppid;
base::strlcpy(entry_.szExeFile, exec_name.c_str(),
sizeof(entry_.szExeFile));
// Start w/ the next entry next time through
++index_of_kinfo_proc_;
// Done
return true;
}
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() {
// Don't need to check the name, we did that w/in CheckForNextProcess.
if (!filter_)
return true;
return filter_->Includes(entry_.pid, entry_.ppid);
return (base::SysWideToUTF8(executable_name_) == entry().exe_file() &&
ProcessIterator::IncludeEntry());
}
......@@ -192,6 +167,23 @@ bool NamedProcessIterator::IncludeEntry() {
// call). Child processes ipc their port, so return something if available,
// otherwise return 0.
//
ProcessMetrics::ProcessMetrics(ProcessHandle process,
ProcessMetrics::PortProvider* port_provider)
: process_(process),
last_time_(0),
last_system_time_(0),
port_provider_(port_provider) {
processor_count_ = base::SysInfo::NumberOfProcessors();
}
// static
ProcessMetrics* ProcessMetrics::CreateProcessMetrics(
ProcessHandle process,
ProcessMetrics::PortProvider* port_provider) {
return new ProcessMetrics(process, port_provider);
}
bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
return false;
}
......
......@@ -25,7 +25,6 @@
#include "base/process_util.h"
#include "base/rand_util.h"
#include "base/scoped_ptr.h"
#include "base/sys_info.h"
#include "base/time.h"
#include "base/waitable_event.h"
......@@ -577,37 +576,6 @@ bool LaunchApp(const CommandLine& cl,
return LaunchApp(cl.argv(), no_files, wait, process_handle);
}
#if !defined(OS_MACOSX)
ProcessMetrics::ProcessMetrics(ProcessHandle process)
#else
ProcessMetrics::ProcessMetrics(ProcessHandle process,
ProcessMetrics::PortProvider* port_provider)
#endif
: process_(process),
last_time_(0),
last_system_time_(0)
#if defined(OS_MACOSX)
, port_provider_(port_provider)
#elif defined(OS_POSIX)
, last_cpu_(0)
#endif
{
processor_count_ = base::SysInfo::NumberOfProcessors();
}
// static
#if !defined(OS_MACOSX)
ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
return new ProcessMetrics(process);
}
#else
ProcessMetrics* ProcessMetrics::CreateProcessMetrics(
ProcessHandle process,
ProcessMetrics::PortProvider* port_provider) {
return new ProcessMetrics(process, port_provider);
}
#endif
ProcessMetrics::~ProcessMetrics() { }
void EnableTerminationOnHeapCorruption() {
......@@ -877,28 +845,6 @@ bool GetAppOutputRestricted(const CommandLine& cl,
return GetAppOutputInternal(cl, &empty_environ, output, max_output, false);
}
int GetProcessCount(const std::wstring& executable_name,
const ProcessFilter* filter) {
int count = 0;
NamedProcessIterator iter(executable_name, filter);
while (iter.NextProcessEntry())
++count;
return count;
}
bool KillProcesses(const std::wstring& executable_name, int exit_code,
const ProcessFilter* filter) {
bool result = true;
const ProcessEntry* entry;
NamedProcessIterator iter(executable_name, filter);
while ((entry = iter.NextProcessEntry()) != NULL)
result = KillProcess((*entry).pid, exit_code, true) && result;
return result;
}
bool WaitForProcessesToExit(const std::wstring& executable_name,
int64 wait_milliseconds,
const ProcessFilter* filter) {
......
This diff is collapsed.
......@@ -222,9 +222,11 @@ bool KillProcessById(ProcessId process_id, int exit_code, bool wait) {
HANDLE process = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE,
FALSE, // Don't inherit handle
process_id);
if (!process)
if (!process) {
DLOG(ERROR) << "Unable to open process " << process_id << " : "
<< GetLastError();
return false;
}
bool ret = KillProcess(process, exit_code, wait);
CloseHandle(process);
return ret;
......@@ -384,33 +386,17 @@ bool WaitForExitCodeWithTimeout(ProcessHandle handle, int* exit_code,
return true;
}
NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name,
const ProcessFilter* filter)
ProcessIterator::ProcessIterator(const ProcessFilter* filter)
: started_iteration_(false),
executable_name_(executable_name),
filter_(filter) {
snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
}
NamedProcessIterator::~NamedProcessIterator() {
ProcessIterator::~ProcessIterator() {
CloseHandle(snapshot_);
}
const ProcessEntry* NamedProcessIterator::NextProcessEntry() {
bool result = false;
do {
result = CheckForNextProcess();
} while (result && !IncludeEntry());
if (result) {
return &entry_;
}
return NULL;
}
bool NamedProcessIterator::CheckForNextProcess() {
bool ProcessIterator::CheckForNextProcess() {
InitProcessEntry(&entry_);
if (!started_iteration_) {
......@@ -421,39 +407,15 @@ bool NamedProcessIterator::CheckForNextProcess() {
return !!Process32Next(snapshot_, &entry_);
}
bool NamedProcessIterator::IncludeEntry() {
return _wcsicmp(executable_name_.c_str(), entry_.szExeFile) == 0 &&
(!filter_ || filter_->Includes(entry_.th32ProcessID,
entry_.th32ParentProcessID));
}
void NamedProcessIterator::InitProcessEntry(ProcessEntry* entry) {
void ProcessIterator::InitProcessEntry(ProcessEntry* entry) {
memset(entry, 0, sizeof(*entry));
entry->dwSize = sizeof(*entry);
}
int GetProcessCount(const std::wstring& executable_name,
const ProcessFilter* filter) {
int count = 0;
NamedProcessIterator iter(executable_name, filter);
while (iter.NextProcessEntry())
++count;
return count;
}
bool KillProcesses(const std::wstring& executable_name, int exit_code,
const ProcessFilter* filter) {
bool result = true;
const ProcessEntry* entry;