internal_linux.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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. 4 5#include "base/process/internal_linux.h" 6 7#include <unistd.h> 8 9#include <string> 10#include <vector> 11 12#include "base/file_util.h" 13#include "base/logging.h" 14#include "base/string_util.h" 15#include "base/strings/string_number_conversions.h" 16#include "base/strings/string_split.h" 17#include "base/threading/thread_restrictions.h" 18 19namespace base { 20namespace internal { 21 22const char kProcDir[] = "/proc"; 23 24const char kStatFile[] = "stat"; 25 26base::FilePath GetProcPidDir(pid_t pid) { 27 return base::FilePath(kProcDir).Append(IntToString(pid)); 28} 29 30pid_t ProcDirSlotToPid(const char* d_name) { 31 int i; 32 for (i = 0; i < NAME_MAX && d_name[i]; ++i) { 33 if (!IsAsciiDigit(d_name[i])) { 34 return 0; 35 } 36 } 37 if (i == NAME_MAX) 38 return 0; 39 40 // Read the process's command line. 41 pid_t pid; 42 std::string pid_string(d_name); 43 if (!StringToInt(pid_string, &pid)) { 44 NOTREACHED(); 45 return 0; 46 } 47 return pid; 48} 49 50bool ReadProcStats(pid_t pid, std::string* buffer) { 51 buffer->clear(); 52 // Synchronously reading files in /proc is safe. 53 ThreadRestrictions::ScopedAllowIO allow_io; 54 55 FilePath stat_file = internal::GetProcPidDir(pid).Append(kStatFile); 56 if (!file_util::ReadFileToString(stat_file, buffer)) { 57 DLOG(WARNING) << "Failed to get process stats."; 58 return false; 59 } 60 return !buffer->empty(); 61} 62 63bool ParseProcStats(const std::string& stats_data, 64 std::vector<std::string>* proc_stats) { 65 // |stats_data| may be empty if the process disappeared somehow. 66 // e.g. http://crbug.com/145811 67 if (stats_data.empty()) 68 return false; 69 70 // The stat file is formatted as: 71 // pid (process name) data1 data2 .... dataN 72 // Look for the closing paren by scanning backwards, to avoid being fooled by 73 // processes with ')' in the name. 74 size_t open_parens_idx = stats_data.find(" ("); 75 size_t close_parens_idx = stats_data.rfind(") "); 76 if (open_parens_idx == std::string::npos || 77 close_parens_idx == std::string::npos || 78 open_parens_idx > close_parens_idx) { 79 DLOG(WARNING) << "Failed to find matched parens in '" << stats_data << "'"; 80 NOTREACHED(); 81 return false; 82 } 83 open_parens_idx++; 84 85 proc_stats->clear(); 86 // PID. 87 proc_stats->push_back(stats_data.substr(0, open_parens_idx)); 88 // Process name without parentheses. 89 proc_stats->push_back( 90 stats_data.substr(open_parens_idx + 1, 91 close_parens_idx - (open_parens_idx + 1))); 92 93 // Split the rest. 94 std::vector<std::string> other_stats; 95 SplitString(stats_data.substr(close_parens_idx + 2), ' ', &other_stats); 96 for (size_t i = 0; i < other_stats.size(); ++i) 97 proc_stats->push_back(other_stats[i]); 98 return true; 99} 100 101int GetProcStatsFieldAsInt(const std::vector<std::string>& proc_stats, 102 ProcStatsFields field_num) { 103 DCHECK_GE(field_num, VM_PPID); 104 CHECK_LT(static_cast<size_t>(field_num), proc_stats.size()); 105 106 int value; 107 return StringToInt(proc_stats[field_num], &value) ? value : 0; 108} 109 110size_t GetProcStatsFieldAsSizeT(const std::vector<std::string>& proc_stats, 111 ProcStatsFields field_num) { 112 DCHECK_GE(field_num, VM_PPID); 113 CHECK_LT(static_cast<size_t>(field_num), proc_stats.size()); 114 115 size_t value; 116 return StringToSizeT(proc_stats[field_num], &value) ? value : 0; 117} 118 119int ReadProcStatsAndGetFieldAsInt(pid_t pid, 120 ProcStatsFields field_num) { 121 std::string stats_data; 122 if (!ReadProcStats(pid, &stats_data)) 123 return 0; 124 std::vector<std::string> proc_stats; 125 if (!ParseProcStats(stats_data, &proc_stats)) 126 return 0; 127 return GetProcStatsFieldAsInt(proc_stats, field_num); 128} 129 130size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid, 131 ProcStatsFields field_num) { 132 std::string stats_data; 133 if (!ReadProcStats(pid, &stats_data)) 134 return 0; 135 std::vector<std::string> proc_stats; 136 if (!ParseProcStats(stats_data, &proc_stats)) 137 return 0; 138 return GetProcStatsFieldAsSizeT(proc_stats, field_num); 139} 140 141} // namespace internal 142} // namespace base 143