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 base::FilePath
GetProcPidDir(pid_t pid
) {
29 return base::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
;
101 SplitString(stats_data
.substr(close_parens_idx
+ 2), ' ', &other_stats
);
102 for (size_t i
= 0; i
< other_stats
.size(); ++i
)
103 proc_stats
->push_back(other_stats
[i
]);
107 typedef std::map
<std::string
, std::string
> ProcStatMap
;
108 void ParseProcStat(const std::string
& contents
, ProcStatMap
* output
) {
109 base::StringPairs key_value_pairs
;
110 SplitStringIntoKeyValuePairs(contents
, ' ', '\n', &key_value_pairs
);
111 for (size_t i
= 0; i
< key_value_pairs
.size(); ++i
) {
112 output
->insert(key_value_pairs
[i
]);
116 int64
GetProcStatsFieldAsInt64(const std::vector
<std::string
>& proc_stats
,
117 ProcStatsFields field_num
) {
118 DCHECK_GE(field_num
, VM_PPID
);
119 CHECK_LT(static_cast<size_t>(field_num
), proc_stats
.size());
122 return StringToInt64(proc_stats
[field_num
], &value
) ? value
: 0;
125 size_t GetProcStatsFieldAsSizeT(const std::vector
<std::string
>& proc_stats
,
126 ProcStatsFields field_num
) {
127 DCHECK_GE(field_num
, VM_PPID
);
128 CHECK_LT(static_cast<size_t>(field_num
), proc_stats
.size());
131 return StringToSizeT(proc_stats
[field_num
], &value
) ? value
: 0;
134 int64
ReadProcStatsAndGetFieldAsInt64(pid_t pid
, ProcStatsFields field_num
) {
135 std::string stats_data
;
136 if (!ReadProcStats(pid
, &stats_data
))
138 std::vector
<std::string
> proc_stats
;
139 if (!ParseProcStats(stats_data
, &proc_stats
))
141 return GetProcStatsFieldAsInt64(proc_stats
, field_num
);
144 size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid
,
145 ProcStatsFields field_num
) {
146 std::string stats_data
;
147 if (!ReadProcStats(pid
, &stats_data
))
149 std::vector
<std::string
> proc_stats
;
150 if (!ParseProcStats(stats_data
, &proc_stats
))
152 return GetProcStatsFieldAsSizeT(proc_stats
, field_num
);
156 FilePath
path("/proc/stat");
157 std::string contents
;
158 if (!ReadProcFile(path
, &contents
))
160 ProcStatMap proc_stat
;
161 ParseProcStat(contents
, &proc_stat
);
162 ProcStatMap::const_iterator btime_it
= proc_stat
.find("btime");
163 if (btime_it
== proc_stat
.end())
166 if (!StringToInt(btime_it
->second
, &btime
))
168 return Time::FromTimeT(btime
);
171 TimeDelta
ClockTicksToTimeDelta(int clock_ticks
) {
172 // This queries the /proc-specific scaling factor which is
173 // conceptually the system hertz. To dump this value on another
175 // od -t dL /proc/self/auxv
176 // and look for the number after 17 in the output; mine is
177 // 0000040 17 100 3 134512692
178 // which means the answer is 100.
179 // It may be the case that this value is always 100.
180 static const int kHertz
= sysconf(_SC_CLK_TCK
);
182 return TimeDelta::FromMicroseconds(
183 Time::kMicrosecondsPerSecond
* clock_ticks
/ kHertz
);
186 } // namespace internal