/third_party/crashpad/crashpad/util/linux/proc_stat_reader.cc

https://github.com/chromium/chromium · C++ · 142 lines · 98 code · 26 blank · 18 comment · 14 complexity · cb648f7aa0cc67e6c827737f49ec9ce3 MD5 · raw file

  1. // Copyright 2017 The Crashpad Authors. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "util/linux/proc_stat_reader.h"
  15. #include <stdio.h>
  16. #include <time.h>
  17. #include <unistd.h>
  18. #include <iterator>
  19. #include "base/files/file_path.h"
  20. #include "base/logging.h"
  21. #include "util/file/file_io.h"
  22. #include "util/misc/lexing.h"
  23. #include "util/misc/time.h"
  24. namespace crashpad {
  25. namespace {
  26. long GetClockTicksPerSecond() {
  27. long clock_ticks_per_s = sysconf(_SC_CLK_TCK);
  28. if (clock_ticks_per_s <= 0) {
  29. PLOG(ERROR) << "sysconf";
  30. }
  31. return clock_ticks_per_s;
  32. }
  33. } // namespace
  34. ProcStatReader::ProcStatReader()
  35. : contents_(), third_column_position_(0), initialized_() {}
  36. ProcStatReader::~ProcStatReader() {}
  37. bool ProcStatReader::Initialize(PtraceConnection* connection, pid_t tid) {
  38. INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
  39. char path[32];
  40. snprintf(path, std::size(path), "/proc/%d/stat", tid);
  41. if (!connection->ReadFileContents(base::FilePath(path), &contents_)) {
  42. return false;
  43. }
  44. // The first column is process ID and the second column is the executable name
  45. // in parentheses. This class only cares about columns after the second, so
  46. // find the start of the third here and save it for later.
  47. // The executable name may have parentheses itself, so find the end of the
  48. // second column by working backwards to find the last closing parens.
  49. size_t stat_pos = contents_.rfind(')');
  50. if (stat_pos == std::string::npos) {
  51. LOG(ERROR) << "format error";
  52. return false;
  53. }
  54. third_column_position_ = contents_.find(' ', stat_pos);
  55. if (third_column_position_ == std::string::npos ||
  56. ++third_column_position_ >= contents_.size()) {
  57. LOG(ERROR) << "format error";
  58. return false;
  59. }
  60. INITIALIZATION_STATE_SET_VALID(initialized_);
  61. return true;
  62. }
  63. bool ProcStatReader::UserCPUTime(timeval* user_time) const {
  64. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  65. return ReadTimeAtIndex(13, user_time);
  66. }
  67. bool ProcStatReader::SystemCPUTime(timeval* system_time) const {
  68. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  69. return ReadTimeAtIndex(14, system_time);
  70. }
  71. bool ProcStatReader::StartTime(const timeval& boot_time,
  72. timeval* start_time) const {
  73. INITIALIZATION_STATE_DCHECK_VALID(initialized_);
  74. timeval time_after_boot;
  75. if (!ReadTimeAtIndex(21, &time_after_boot)) {
  76. return false;
  77. }
  78. timeradd(&boot_time, &time_after_boot, start_time);
  79. return true;
  80. }
  81. bool ProcStatReader::FindColumn(int col_index, const char** column) const {
  82. size_t position = third_column_position_;
  83. for (int index = 2; index < col_index; ++index) {
  84. position = contents_.find(' ', position);
  85. if (position == std::string::npos) {
  86. break;
  87. }
  88. ++position;
  89. }
  90. if (position >= contents_.size()) {
  91. LOG(ERROR) << "format error";
  92. return false;
  93. }
  94. *column = &contents_[position];
  95. return true;
  96. }
  97. bool ProcStatReader::ReadTimeAtIndex(int index, timeval* time_val) const {
  98. const char* ticks_ptr;
  99. if (!FindColumn(index, &ticks_ptr)) {
  100. return false;
  101. }
  102. uint64_t ticks;
  103. if (!AdvancePastNumber<uint64_t>(&ticks_ptr, &ticks)) {
  104. LOG(ERROR) << "format error";
  105. return false;
  106. }
  107. static long clock_ticks_per_s = GetClockTicksPerSecond();
  108. if (clock_ticks_per_s <= 0) {
  109. return false;
  110. }
  111. time_val->tv_sec = ticks / clock_ticks_per_s;
  112. time_val->tv_usec = (ticks % clock_ticks_per_s) *
  113. (static_cast<long>(1E6) / clock_ticks_per_s);
  114. return true;
  115. }
  116. } // namespace crashpad