1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/process/internal_linux.h"
13 #include "base/files/file_util.h"
14 #include "base/logging.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_split.h"
17 #include "base/strings/string_util.h"
18 #include "base/threading/thread_restrictions.h"
19 #include "base/time/time.h"
24 const char kProcDir
[] = "/proc";
26 const char kStatFile
[] = "stat";
28 FilePath
GetProcPidDir(pid_t pid
) {
29 return FilePath(kProcDir
).Append(IntToString(pid
));
32 pid_t
ProcDirSlotToPid(const char* d_name
) {
34 for (i
= 0; i
< NAME_MAX
&& d_name
[i
]; ++i
) {
35 if (!IsAsciiDigit(d_name
[i
])) {
42 // Read the process's command line.
44 std::string
pid_string(d_name
);
45 if (!StringToInt(pid_string
, &pid
)) {
52 bool ReadProcFile(const FilePath
& file
, std::string
* buffer
) {
54 // Synchronously reading files in /proc is safe.
55 ThreadRestrictions::ScopedAllowIO allow_io
;
57 if (!ReadFileToString(file
, buffer
)) {
58 DLOG(WARNING
) << "Failed to read " << file
.MaybeAsASCII();
61 return !buffer
->empty();
64 bool ReadProcStats(pid_t pid
, std::string
* buffer
) {
65 FilePath stat_file
= internal::GetProcPidDir(pid
).Append(kStatFile
);
66 return ReadProcFile(stat_file
, buffer
);
69 bool ParseProcStats(const std::string
& stats_data
,
70 std::vector
<std::string
>* proc_stats
) {
71 // |stats_data| may be empty if the process disappeared somehow.
72 // e.g. http://crbug.com/145811
73 if (stats_data
.empty())
76 // The stat file is formatted as:
77 // pid (process name) data1 data2 .... dataN
78 // Look for the closing paren by scanning backwards, to avoid being fooled by
79 // processes with ')' in the name.
80 size_t open_parens_idx
= stats_data
.find(" (");
81 size_t close_parens_idx
= stats_data
.rfind(") ");
82 if (open_parens_idx
== std::string::npos
||
83 close_parens_idx
== std::string::npos
||
84 open_parens_idx
> close_parens_idx
) {
85 DLOG(WARNING
) << "Failed to find matched parens in '" << stats_data
<< "'";
93 proc_stats
->push_back(stats_data
.substr(0, open_parens_idx
));
94 // Process name without parentheses.
95 proc_stats
->push_back(
96 stats_data
.substr(open_parens_idx
+ 1,
97 close_parens_idx
- (open_parens_idx
+ 1)));
100 std::vector
<std::string
> other_stats
= SplitString(
101 stats_data
.substr(close_parens_idx
+ 2), " ",
102 base::TRIM_WHITESPACE
, base::SPLIT_WANT_ALL
);
103 for (size_t i
= 0; i
< other_stats
.size(); ++i
)
104 proc_stats
->push_back(other_stats
[i
]);
108 typedef std::map
<std::string
, std::string
> ProcStatMap
;
109 void ParseProcStat(const std::string
& contents
, ProcStatMap
* output
) {
110 StringPairs key_value_pairs
;
111 SplitStringIntoKeyValuePairs(contents
, ' ', '\n', &key_value_pairs
);
112 for (size_t i
= 0; i
< key_value_pairs
.size(); ++i
) {
113 output
->insert(key_value_pairs
[i
]);
117 int64
GetProcStatsFieldAsInt64(const std::vector
<std::string
>& proc_stats
,
118 ProcStatsFields field_num
) {
119 DCHECK_GE(field_num
, VM_PPID
);
120 CHECK_LT(static_cast<size_t>(field_num
), proc_stats
.size());
123 return StringToInt64(proc_stats
[field_num
], &value
) ? value
: 0;
126 size_t GetProcStatsFieldAsSizeT(const std::vector
<std::string
>& proc_stats
,
127 ProcStatsFields field_num
) {
128 DCHECK_GE(field_num
, VM_PPID
);
129 CHECK_LT(static_cast<size_t>(field_num
), proc_stats
.size());
132 return StringToSizeT(proc_stats
[field_num
], &value
) ? value
: 0;
135 int64
ReadProcStatsAndGetFieldAsInt64(pid_t pid
, ProcStatsFields field_num
) {
136 std::string stats_data
;
137 if (!ReadProcStats(pid
, &stats_data
))
139 std::vector
<std::string
> proc_stats
;
140 if (!ParseProcStats(stats_data
, &proc_stats
))
142 return GetProcStatsFieldAsInt64(proc_stats
, field_num
);
145 size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid
,
146 ProcStatsFields field_num
) {
147 std::string stats_data
;
148 if (!ReadProcStats(pid
, &stats_data
))
150 std::vector
<std::string
> proc_stats
;
151 if (!ParseProcStats(stats_data
, &proc_stats
))
153 return GetProcStatsFieldAsSizeT(proc_stats
, field_num
);
157 FilePath
path("/proc/stat");
158 std::string contents
;
159 if (!ReadProcFile(path
, &contents
))
161 ProcStatMap proc_stat
;
162 ParseProcStat(contents
, &proc_stat
);
163 ProcStatMap::const_iterator btime_it
= proc_stat
.find("btime");
164 if (btime_it
== proc_stat
.end())
167 if (!StringToInt(btime_it
->second
, &btime
))
169 return Time::FromTimeT(btime
);
172 TimeDelta
ClockTicksToTimeDelta(int clock_ticks
) {
173 // This queries the /proc-specific scaling factor which is
174 // conceptually the system hertz. To dump this value on another
176 // od -t dL /proc/self/auxv
177 // and look for the number after 17 in the output; mine is
178 // 0000040 17 100 3 134512692
179 // which means the answer is 100.
180 // It may be the case that this value is always 100.
181 static const int kHertz
= sysconf(_SC_CLK_TCK
);
183 return TimeDelta::FromMicroseconds(
184 Time::kMicrosecondsPerSecond
* clock_ticks
/ kHertz
);
187 } // namespace internal