summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-05 21:44:13 +0000
committermark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-05 21:44:13 +0000
commit962dd31f9cff7017d90da505e077ea84db9c5e48 (patch)
tree821a70988ea4e963be58314c5b9b7becab7312fe
parent3115504c55a338fb3de3684a85b2383b4c4dbbc0 (diff)
downloadchromium_src-962dd31f9cff7017d90da505e077ea84db9c5e48.zip
chromium_src-962dd31f9cff7017d90da505e077ea84db9c5e48.tar.gz
chromium_src-962dd31f9cff7017d90da505e077ea84db9c5e48.tar.bz2
Implement NamedProcessIterator in base/process_util_mac.mm. Patch by Naoki
Takano <takano.naoki@gmail.com> Review URL: http://codereview.chromium.org/18192 Review URL: http://codereview.chromium.org/21097 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@9263 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--AUTHORS1
-rw-r--r--base/process_util.h12
-rw-r--r--base/process_util_linux.cc57
-rw-r--r--base/process_util_mac.mm118
-rw-r--r--base/process_util_posix.cc57
-rw-r--r--base/process_util_unittest.cc6
6 files changed, 175 insertions, 76 deletions
diff --git a/AUTHORS b/AUTHORS
index dd639a9..4cc03a6 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -20,6 +20,7 @@ Comodo CA Limited
Torchmobile Inc.
Craig Schlenter <craig.schlenter@gmail.com>
Ibrar Ahmed <ibrar.ahmad@gmail.com>
+Naoki Takano <takano.naoki@gmail.com>
Fabien Tassin <fta@sofaraway.org>
Kunal Thakar <kunalt@gmail.com>
Mohamed Mansour <m0.interactive@gmail.com>
diff --git a/base/process_util.h b/base/process_util.h
index ec858bd..8c4c5d4 100644
--- a/base/process_util.h
+++ b/base/process_util.h
@@ -20,6 +20,7 @@
#endif
#include <string>
+#include <vector>
#include "base/command_line.h"
#include "base/process.h"
@@ -28,10 +29,11 @@
typedef PROCESSENTRY32 ProcessEntry;
typedef IO_COUNTERS IoCounters;
#elif defined(OS_POSIX)
+// TODO(port): we should not rely on a Win32 structure.
struct ProcessEntry {
int pid;
int ppid;
- char szExeFile[NAME_MAX+1];
+ char szExeFile[NAME_MAX + 1];
};
struct IoCounters {
@@ -44,6 +46,10 @@ struct IoCounters {
};
#endif
+#if defined(OS_MACOSX)
+struct kinfo_proc;
+#endif
+
namespace base {
// A minimalistic but hopefully cross-platform set of exit codes.
@@ -215,9 +221,9 @@ class NamedProcessIterator {
#elif defined(OS_LINUX)
DIR *procfs_dir_;
#elif defined(OS_MACOSX)
- // probably kvm_t *kvmd_;
+ std::vector<kinfo_proc> kinfo_procs_;
+ size_t index_of_kinfo_proc_;
#endif
-
ProcessEntry entry_;
const ProcessFilter* filter_;
diff --git a/base/process_util_linux.cc b/base/process_util_linux.cc
index 8f83212..2253ff2 100644
--- a/base/process_util_linux.cc
+++ b/base/process_util_linux.cc
@@ -14,7 +14,6 @@
#include "base/file_util.h"
#include "base/logging.h"
-#include "base/platform_thread.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "base/time.h"
@@ -202,62 +201,6 @@ bool NamedProcessIterator::IncludeEntry() {
return filter_->Includes(entry_.pid, entry_.ppid);
}
-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,
- int wait_milliseconds,
- const ProcessFilter* filter) {
- bool result = false;
-
- // TODO(port): This is inefficient, but works if there are multiple procs.
- // TODO(port): use waitpid to avoid leaving zombies around
-
- base::Time end_time = base::Time::Now() +
- base::TimeDelta::FromMilliseconds(wait_milliseconds);
- do {
- NamedProcessIterator iter(executable_name, filter);
- if (!iter.NextProcessEntry()) {
- result = true;
- break;
- }
- PlatformThread::Sleep(100);
- } while ((base::Time::Now() - end_time) > base::TimeDelta());
-
- return result;
-}
-
-bool CleanupProcesses(const std::wstring& executable_name,
- int wait_milliseconds,
- int exit_code,
- const ProcessFilter* filter) {
- bool exited_cleanly =
- WaitForProcessesToExit(executable_name, wait_milliseconds,
- filter);
- if (!exited_cleanly)
- KillProcesses(executable_name, exit_code, filter);
- return exited_cleanly;
-}
-
// To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING
// in your kernel configuration.
bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) {
diff --git a/base/process_util_mac.mm b/base/process_util_mac.mm
index 6dd865b..501205c 100644
--- a/base/process_util_mac.mm
+++ b/base/process_util_mac.mm
@@ -3,16 +3,21 @@
// found in the LICENSE file.
-#include "base/logging.h"
#include "base/process_util.h"
#import <Cocoa/Cocoa.h>
#include <crt_externs.h>
#include <spawn.h>
-#include <string>
+#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <string>
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/time.h"
+
namespace base {
bool LaunchApp(const std::vector<std::string>& argv,
@@ -73,7 +78,7 @@ bool LaunchApp(const std::vector<std::string>& argv,
if (wait)
waitpid(pid, 0, 0);
- if(process_handle)
+ if (process_handle)
*process_handle = pid;
}
@@ -87,21 +92,106 @@ bool LaunchApp(const CommandLine& cl,
return LaunchApp(cl.argv(), no_files, wait, process_handle);
}
-bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) {
- // TODO(pinkerton): can we implement this? On linux it relies on /proc.
- return false;
+NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name,
+ const ProcessFilter* filter)
+ : executable_name_(executable_name),
+ index_of_kinfo_proc_(0),
+ filter_(filter) {
}
-int GetProcessCount(const std::wstring& executable_name,
- const ProcessFilter* filter) {
- NOTIMPLEMENTED();
- return 0;
+NamedProcessIterator::~NamedProcessIterator() {
}
-bool CleanupProcesses(const std::wstring& executable_name,
- int wait_milliseconds,
- int exit_code,
- const ProcessFilter* filter) {
+const ProcessEntry* NamedProcessIterator::NextProcessEntry() {
+ // Every call, you have to get new kinfo_procs_.
+ // Because the process status might be changed.
+ int num_of_kinfo_proc = 0;
+ index_of_kinfo_proc_ = 0;
+ int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
+ size_t len = 0;
+
+ if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0)
+ return NULL;
+
+ num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+ // Leave some spare room for process table growth.
+ 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)
+ return NULL;
+
+ num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+ kinfo_procs_.resize(num_of_kinfo_proc);
+
+ bool result = false;
+ do {
+ result = CheckForNextProcess();
+ } while (result && !IncludeEntry());
+
+ if (result)
+ return &entry_;
+
+ return NULL;
+}
+
+bool NamedProcessIterator::CheckForNextProcess() {
+ std::string exec_name;
+ kinfo_proc* kinfo = NULL;
+ for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
+ if (kinfo_procs_[index_of_kinfo_proc_].kp_proc.p_stat != SZOMB) {
+ kinfo = &kinfo_procs_[index_of_kinfo_proc_];
+
+ int mib[] = { KERN_PROCARGS, KERN_PROCARGS, kinfo->kp_proc.p_pid };
+
+ size_t data_len = 0;
+ if (sysctl(mib, arraysize(mib), NULL, &data_len, NULL, 0) < 0)
+ continue;
+
+ std::string data;
+ data.resize(data_len);
+ if (sysctl(mib, arraysize(mib), &data[0], &data_len, NULL, 0) < 0)
+ continue;
+
+ // "data" has absolute process path with '/',
+ // so we get the last part as execution process name.
+
+ int exec_name_end = data.find('\0');
+ int last_slash = data.rfind('/', exec_name_end);
+
+ // If the index is not -1, it means valid exec name is found.
+ // Get the exec name and store the name into exec_name and break.
+ // "last_slash" point is '/', so get substr from the next.
+ if (last_slash != -1) {
+ exec_name = data.substr(exec_name_end - last_slash - 1);
+ } else {
+ exec_name = data.substr(0, exec_name_end);
+ }
+ break;
+ }
+ }
+
+ if (index_of_kinfo_proc_ >= kinfo_procs_.size())
+ return false;
+
+ entry_.pid = kinfo->kp_proc.p_pid;
+ entry_.ppid = kinfo->kp_proc.p_oppid;
+
+ base::strlcpy(entry_.szExeFile, exec_name.c_str(), sizeof(entry_.szExeFile));
+
+ return true;
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+ if (WideToUTF8(executable_name_) != entry_.szExeFile)
+ return false;
+ if (!filter_)
+ return true;
+ return filter_->Includes(entry_.pid, entry_.ppid);
+}
+
+bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) {
+ // TODO(pinkerton): can we implement this? On linux it relies on /proc.
NOTIMPLEMENTED();
return false;
}
diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc
index d8fefca..680cacc 100644
--- a/base/process_util_posix.cc
+++ b/base/process_util_posix.cc
@@ -17,6 +17,7 @@
#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/platform_thread.h"
#include "base/process_util.h"
#include "base/sys_info.h"
#include "base/time.h"
@@ -270,4 +271,60 @@ int ProcessMetrics::GetCPUUsage() {
return cpu;
}
+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,
+ int wait_milliseconds,
+ const ProcessFilter* filter) {
+ bool result = false;
+
+ // TODO(port): This is inefficient, but works if there are multiple procs.
+ // TODO(port): use waitpid to avoid leaving zombies around
+
+ base::Time end_time = base::Time::Now() +
+ base::TimeDelta::FromMilliseconds(wait_milliseconds);
+ do {
+ NamedProcessIterator iter(executable_name, filter);
+ if (!iter.NextProcessEntry()) {
+ result = true;
+ break;
+ }
+ PlatformThread::Sleep(100);
+ } while ((base::Time::Now() - end_time) > base::TimeDelta());
+
+ return result;
+}
+
+bool CleanupProcesses(const std::wstring& executable_name,
+ int wait_milliseconds,
+ int exit_code,
+ const ProcessFilter* filter) {
+ bool exited_cleanly =
+ WaitForProcessesToExit(executable_name, wait_milliseconds,
+ filter);
+ if (!exited_cleanly)
+ KillProcesses(executable_name, exit_code, filter);
+ return exited_cleanly;
+}
+
} // namespace base
diff --git a/base/process_util_unittest.cc b/base/process_util_unittest.cc
index 0b3bc21..1c99733 100644
--- a/base/process_util_unittest.cc
+++ b/base/process_util_unittest.cc
@@ -55,9 +55,12 @@ MULTIPROCESS_TEST_MAIN(SlowChildProcess) {
#define EXE_SUFFIX L""
#endif
+#if defined(OS_MACOSX)
// TODO(port): finish port on Mac
-#if !defined(OS_MACOSX)
+TEST_F(ProcessUtilTest, DISABLED_KillSlowChild) {
+#else
TEST_F(ProcessUtilTest, KillSlowChild) {
+#endif
remove("SlowChildProcess.die");
int oldcount = GetProcessCount(L"base_unittests" EXE_SUFFIX, 0);
@@ -70,7 +73,6 @@ TEST_F(ProcessUtilTest, KillSlowChild) {
EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000));
EXPECT_EQ(oldcount, GetProcessCount(L"base_unittests" EXE_SUFFIX, 0));
}
-#endif
// TODO(estade): if possible, port these 2 tests.
#if defined(OS_WIN)