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 typedef std::pair
<std::string
, std::string
> StringPair
;
110 std::vector
<StringPair
> key_value_pairs
;
111 SplitStringIntoKeyValuePairs(contents
, ' ', '\n', &key_value_pairs
);
112 for (size_t i
= 0; i
< key_value_pairs
.size(); ++i
) {
113 const StringPair
& key_value_pair
= key_value_pairs
[i
];
114 output
->insert(key_value_pair
);
118 int64
GetProcStatsFieldAsInt64(const std::vector
<std::string
>& proc_stats
,
119 ProcStatsFields field_num
) {
120 DCHECK_GE(field_num
, VM_PPID
);
121 CHECK_LT(static_cast<size_t>(field_num
), proc_stats
.size());
124 return StringToInt64(proc_stats
[field_num
], &value
) ? value
: 0;
127 size_t GetProcStatsFieldAsSizeT(const std::vector
<std::string
>& proc_stats
,
128 ProcStatsFields field_num
) {
129 DCHECK_GE(field_num
, VM_PPID
);
130 CHECK_LT(static_cast<size_t>(field_num
), proc_stats
.size());
133 return StringToSizeT(proc_stats
[field_num
], &value
) ? value
: 0;
136 int64
ReadProcStatsAndGetFieldAsInt64(pid_t pid
, ProcStatsFields field_num
) {
137 std::string stats_data
;
138 if (!ReadProcStats(pid
, &stats_data
))
140 std::vector
<std::string
> proc_stats
;
141 if (!ParseProcStats(stats_data
, &proc_stats
))
143 return GetProcStatsFieldAsInt64(proc_stats
, field_num
);
146 size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid
,
147 ProcStatsFields field_num
) {
148 std::string stats_data
;
149 if (!ReadProcStats(pid
, &stats_data
))
151 std::vector
<std::string
> proc_stats
;
152 if (!ParseProcStats(stats_data
, &proc_stats
))
154 return GetProcStatsFieldAsSizeT(proc_stats
, field_num
);
158 FilePath
path("/proc/stat");
159 std::string contents
;
160 if (!ReadProcFile(path
, &contents
))
162 ProcStatMap proc_stat
;
163 ParseProcStat(contents
, &proc_stat
);
164 ProcStatMap::const_iterator btime_it
= proc_stat
.find("btime");
165 if (btime_it
== proc_stat
.end())
168 if (!StringToInt(btime_it
->second
, &btime
))
170 return Time::FromTimeT(btime
);
173 TimeDelta
ClockTicksToTimeDelta(int clock_ticks
) {
174 // This queries the /proc-specific scaling factor which is
175 // conceptually the system hertz. To dump this value on another
177 // od -t dL /proc/self/auxv
178 // and look for the number after 17 in the output; mine is
179 // 0000040 17 100 3 134512692
180 // which means the answer is 100.
181 // It may be the case that this value is always 100.
182 static const int kHertz
= sysconf(_SC_CLK_TCK
);
184 return TimeDelta::FromMicroseconds(
185 Time::kMicrosecondsPerSecond
* clock_ticks
/ kHertz
);
188 } // namespace internal