Index: base/process/internal_linux.cc |
diff --git a/base/process/internal_linux.cc b/base/process/internal_linux.cc |
index 7da50b35082a8e28b06981760731dd2a035941e1..ee1107c1792aa44cf4e3a4bb3086562d98ea4820 100644 |
--- a/base/process/internal_linux.cc |
+++ b/base/process/internal_linux.cc |
@@ -6,6 +6,7 @@ |
#include <unistd.h> |
+#include <map> |
#include <string> |
#include <vector> |
@@ -15,6 +16,7 @@ |
#include "base/strings/string_split.h" |
#include "base/strings/string_util.h" |
#include "base/threading/thread_restrictions.h" |
+#include "base/time/time.h" |
namespace base { |
namespace internal { |
@@ -47,19 +49,23 @@ pid_t ProcDirSlotToPid(const char* d_name) { |
return pid; |
} |
-bool ReadProcStats(pid_t pid, std::string* buffer) { |
+bool ReadProcFile(const FilePath& file, std::string* buffer) { |
buffer->clear(); |
// Synchronously reading files in /proc is safe. |
ThreadRestrictions::ScopedAllowIO allow_io; |
- FilePath stat_file = internal::GetProcPidDir(pid).Append(kStatFile); |
- if (!file_util::ReadFileToString(stat_file, buffer)) { |
- DLOG(WARNING) << "Failed to get process stats."; |
+ if (!file_util::ReadFileToString(file, buffer)) { |
+ DLOG(WARNING) << "Failed to read " << file.MaybeAsASCII(); |
return false; |
} |
return !buffer->empty(); |
} |
+bool ReadProcStats(pid_t pid, std::string* buffer) { |
+ FilePath stat_file = internal::GetProcPidDir(pid).Append(kStatFile); |
+ return ReadProcFile(stat_file, buffer); |
+} |
+ |
bool ParseProcStats(const std::string& stats_data, |
std::vector<std::string>* proc_stats) { |
// |stats_data| may be empty if the process disappeared somehow. |
@@ -98,6 +104,17 @@ bool ParseProcStats(const std::string& stats_data, |
return true; |
} |
+typedef std::map<std::string, std::string> ProcStatMap; |
+void ParseProcStat(const std::string& contents, ProcStatMap* output) { |
+ typedef std::pair<std::string, std::string> StringPair; |
+ std::vector<StringPair> key_value_pairs; |
+ SplitStringIntoKeyValuePairs(contents, ' ', '\n', &key_value_pairs); |
+ for (size_t i = 0; i < key_value_pairs.size(); ++i) { |
+ const StringPair& key_value_pair = key_value_pairs[i]; |
+ output->insert(key_value_pair); |
+ } |
+} |
+ |
int GetProcStatsFieldAsInt(const std::vector<std::string>& proc_stats, |
ProcStatsFields field_num) { |
DCHECK_GE(field_num, VM_PPID); |
@@ -138,5 +155,36 @@ size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid, |
return GetProcStatsFieldAsSizeT(proc_stats, field_num); |
} |
+Time GetBootTime() { |
+ FilePath path("/proc/stat"); |
+ std::string contents; |
+ if (!ReadProcFile(path, &contents)) |
+ return Time(); |
+ ProcStatMap proc_stat; |
+ ParseProcStat(contents, &proc_stat); |
+ ProcStatMap::const_iterator btime_it = proc_stat.find("btime"); |
+ if (btime_it == proc_stat.end()) |
+ return Time(); |
+ int btime; |
+ if (!StringToInt(btime_it->second, &btime)) |
+ return Time(); |
+ return Time::FromTimeT(btime); |
+} |
+ |
+TimeDelta ClockTicksToTimeDelta(int clock_ticks) { |
+ // This queries the /proc-specific scaling factor which is |
+ // conceptually the system hertz. To dump this value on another |
+ // system, try |
+ // od -t dL /proc/self/auxv |
+ // and look for the number after 17 in the output; mine is |
+ // 0000040 17 100 3 134512692 |
+ // which means the answer is 100. |
+ // It may be the case that this value is always 100. |
+ static const int kHertz = sysconf(_SC_CLK_TCK); |
+ |
+ return TimeDelta::FromMicroseconds( |
+ Time::kMicrosecondsPerSecond * clock_ticks / kHertz); |
+} |
+ |
} // namespace internal |
} // namespace base |