summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/process_util.h5
-rw-r--r--base/process_util_linux.cc46
-rw-r--r--base/process_util_mac.mm15
-rw-r--r--net/test/test_server_posix.cc51
4 files changed, 107 insertions, 10 deletions
diff --git a/base/process_util.h b/base/process_util.h
index c513f3d..6876e88 100644
--- a/base/process_util.h
+++ b/base/process_util.h
@@ -67,10 +67,15 @@ struct ProcessEntry {
ProcessId ppid_;
ProcessId gid_;
std::string exe_file_;
+ std::vector<std::string> cmd_line_args_;
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_;
+ }
};
struct IoCounters {
diff --git a/base/process_util_linux.cc b/base/process_util_linux.cc
index 43e1a5c..4c034c4 100644
--- a/base/process_util_linux.cc
+++ b/base/process_util_linux.cc
@@ -31,15 +31,34 @@ enum ParsingState {
};
// Reads /proc/<pid>/stat and populates |proc_stats| with the values split by
-// spaces.
-void GetProcStats(pid_t pid, std::vector<std::string>* proc_stats) {
+// spaces. Returns true if successful.
+bool GetProcStats(pid_t pid, std::vector<std::string>* proc_stats) {
FilePath stat_file("/proc");
stat_file = stat_file.Append(base::IntToString(pid));
stat_file = stat_file.Append("stat");
std::string mem_stats;
if (!file_util::ReadFileToString(stat_file, &mem_stats))
- return;
+ return false;
SplitString(mem_stats, ' ', proc_stats);
+ return true;
+}
+
+// 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) {
+ FilePath cmd_line_file("/proc");
+ cmd_line_file = cmd_line_file.Append(base::IntToString(pid));
+ cmd_line_file = cmd_line_file.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
@@ -109,6 +128,7 @@ bool ProcessIterator::CheckForNextProcess() {
dirent* slot = 0;
const char* openparen;
const char* closeparen;
+ std::vector<std::string> cmd_line_args;
// Arbitrarily guess that there will never be more than 200 non-process
// files in /proc. Hardy has 53.
@@ -134,6 +154,12 @@ bool ProcessIterator::CheckForNextProcess() {
continue;
}
+ // Read the process's command line.
+ std::string pid_string(slot->d_name);
+ int pid;
+ if (StringToInt(pid_string, &pid) && !GetProcCmdline(pid, &cmd_line_args))
+ return false;
+
// Read the process's status.
char buf[NAME_MAX + 12];
sprintf(buf, "/proc/%s/stat", slot->d_name);
@@ -175,6 +201,8 @@ bool ProcessIterator::CheckForNextProcess() {
entry_.ppid_ = atoi(closeparen + 3);
entry_.gid_ = atoi(strchr(closeparen + 4, ' '));
+ entry_.cmd_line_args_.assign(cmd_line_args.begin(), cmd_line_args.end());
+
// 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;
@@ -206,7 +234,8 @@ ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
// On linux, we return vsize.
size_t ProcessMetrics::GetPagefileUsage() const {
std::vector<std::string> proc_stats;
- GetProcStats(process_, &proc_stats);
+ if (!GetProcStats(process_, &proc_stats))
+ LOG(WARNING) << "Failed to get process stats.";
const size_t kVmSize = 22;
if (proc_stats.size() > kVmSize) {
int vm_size;
@@ -219,7 +248,8 @@ size_t ProcessMetrics::GetPagefileUsage() const {
// On linux, we return the high water mark of vsize.
size_t ProcessMetrics::GetPeakPagefileUsage() const {
std::vector<std::string> proc_stats;
- GetProcStats(process_, &proc_stats);
+ if (!GetProcStats(process_, &proc_stats))
+ LOG(WARNING) << "Failed to get process stats.";
const size_t kVmPeak = 21;
if (proc_stats.size() > kVmPeak) {
int vm_peak;
@@ -232,7 +262,8 @@ size_t ProcessMetrics::GetPeakPagefileUsage() const {
// On linux, we return RSS.
size_t ProcessMetrics::GetWorkingSetSize() const {
std::vector<std::string> proc_stats;
- GetProcStats(process_, &proc_stats);
+ if (!GetProcStats(process_, &proc_stats))
+ LOG(WARNING) << "Failed to get process stats.";
const size_t kVmRss = 23;
if (proc_stats.size() > kVmRss) {
int num_pages;
@@ -245,7 +276,8 @@ size_t ProcessMetrics::GetWorkingSetSize() const {
// On linux, we return the high water mark of RSS.
size_t ProcessMetrics::GetPeakWorkingSetSize() const {
std::vector<std::string> proc_stats;
- GetProcStats(process_, &proc_stats);
+ if (!GetProcStats(process_, &proc_stats))
+ LOG(WARNING) << "Failed to get process stats.";
const size_t kVmHwm = 23;
if (proc_stats.size() > kVmHwm) {
int num_pages;
diff --git a/base/process_util_mac.mm b/base/process_util_mac.mm
index 2ea59a0..0865360 100644
--- a/base/process_util_mac.mm
+++ b/base/process_util_mac.mm
@@ -129,14 +129,23 @@ bool ProcessIterator::CheckForNextProcess() {
continue;
}
- // Data starts w/ the full path null termed, so we have to extract just the
- // executable name from the path.
-
+ // |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) {
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;
diff --git a/net/test/test_server_posix.cc b/net/test/test_server_posix.cc
index 262845c..6e65bcf 100644
--- a/net/test/test_server_posix.cc
+++ b/net/test/test_server_posix.cc
@@ -4,9 +4,52 @@
#include "net/test/test_server.h"
+#include <vector>
+
#include "base/file_util.h"
#include "base/logging.h"
+#include "base/process_util.h"
#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+
+namespace {
+
+// Helper class used to detect and kill orphaned python test server processes.
+// Checks if the command line of a process contains |path_string| (the path
+// from which the test server was launched) and |port_string| (the port used by
+// the test server), and if the parent pid of the process is 1 (indicating that
+// it is an orphaned process).
+class OrphanedTestServerFilter : public base::ProcessFilter {
+ public:
+ OrphanedTestServerFilter(
+ const std::string& path_string, const std::string& port_string)
+ : path_string_(path_string),
+ port_string_(port_string) {}
+
+ virtual bool Includes(const base::ProcessEntry& entry) const {
+ if (entry.parent_pid() != 1)
+ return false;
+ bool found_path_string = false;
+ bool found_port_string = false;
+ for (std::vector<std::string>::const_iterator it =
+ entry.cmd_line_args().begin();
+ it != entry.cmd_line_args().end();
+ ++it) {
+ if (it->find(path_string_) != std::string::npos)
+ found_path_string = true;
+ if (it->find(port_string_) != std::string::npos)
+ found_port_string = true;
+ }
+ return found_path_string && found_port_string;
+ }
+
+ private:
+ std::string path_string_;
+ std::string port_string_;
+ DISALLOW_COPY_AND_ASSIGN(OrphanedTestServerFilter);
+};
+
+} // namespace
namespace net {
bool TestServer::LaunchPython(const FilePath& testserver_path) {
@@ -47,6 +90,14 @@ bool TestServer::LaunchPython(const FilePath& testserver_path) {
command_line.push_back("--startup-pipe=" + base::IntToString(pipefd[1]));
+ // Try to kill any orphaned testserver processes that may be running.
+ OrphanedTestServerFilter filter(testserver_path.value(),
+ base::IntToString(host_port_pair_.port()));
+ if (!base::KillProcesses(L"python", -1, &filter)) {
+ LOG(WARNING) << "Failed to clean up older orphaned testserver instances.";
+ }
+
+ // Launch a new testserver process.
if (!base::LaunchApp(command_line, map_write_fd, false, &process_handle_)) {
LOG(ERROR) << "Failed to launch " << command_line[0] << " ...";
return false;