mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
linux: Refactor reading start time from the stat file
Bug: crashpad:30 Change-Id: Ie8137db2a5b6f2d4947df108d1fb5bdd9f8ab391 Reviewed-on: https://chromium-review.googlesource.com/580448 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
37f20f7b14
commit
9299d409ab
138
util/linux/proc_stat_reader.cc
Normal file
138
util/linux/proc_stat_reader.cc
Normal file
@ -0,0 +1,138 @@
|
||||
// Copyright 2017 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "util/linux/proc_stat_reader.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/logging.h"
|
||||
#include "util/file/file_io.h"
|
||||
#include "util/misc/lexing.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
namespace {
|
||||
|
||||
void SubtractTimespec(const timespec& t1,
|
||||
const timespec& t2,
|
||||
timespec* result) {
|
||||
result->tv_sec = t1.tv_sec - t2.tv_sec;
|
||||
result->tv_nsec = t1.tv_nsec - t2.tv_nsec;
|
||||
if (result->tv_nsec < 0) {
|
||||
result->tv_sec -= 1;
|
||||
result->tv_nsec += static_cast<long>(1E9);
|
||||
}
|
||||
}
|
||||
|
||||
void TimespecToTimeval(const timespec& ts, timeval* tv) {
|
||||
tv->tv_sec = ts.tv_sec;
|
||||
tv->tv_usec = ts.tv_nsec / 1000;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ProcStatReader::ProcStatReader() : tid_(-1) {}
|
||||
|
||||
ProcStatReader::~ProcStatReader() {}
|
||||
|
||||
bool ProcStatReader::Initialize(pid_t tid) {
|
||||
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
||||
// This might do more in the future.
|
||||
tid_ = tid;
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProcStatReader::StartTime(timeval* start_time) const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
std::string stat_contents;
|
||||
if (!ReadFile(&stat_contents)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The process start time is the 22nd column.
|
||||
// The second column is the executable name in parentheses.
|
||||
// The executable name may have parentheses itself, so find the end of the
|
||||
// second column by working backwards to find the last closing parens and
|
||||
// then count forward to the 22nd column.
|
||||
size_t stat_pos = stat_contents.rfind(')');
|
||||
if (stat_pos == std::string::npos) {
|
||||
LOG(ERROR) << "format error";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int index = 1; index < 21; ++index) {
|
||||
stat_pos = stat_contents.find(' ', stat_pos);
|
||||
if (stat_pos == std::string::npos) {
|
||||
break;
|
||||
}
|
||||
++stat_pos;
|
||||
}
|
||||
if (stat_pos >= stat_contents.size()) {
|
||||
LOG(ERROR) << "format error";
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* ticks_ptr = &stat_contents[stat_pos];
|
||||
|
||||
// start time is in jiffies instead of clock ticks pre 2.6.
|
||||
uint64_t ticks_after_boot;
|
||||
if (!AdvancePastNumber<uint64_t>(&ticks_ptr, &ticks_after_boot)) {
|
||||
LOG(ERROR) << "format error";
|
||||
return false;
|
||||
}
|
||||
long clock_ticks_per_s = sysconf(_SC_CLK_TCK);
|
||||
if (clock_ticks_per_s <= 0) {
|
||||
PLOG(ERROR) << "sysconf";
|
||||
return false;
|
||||
}
|
||||
timeval time_after_boot;
|
||||
time_after_boot.tv_sec = ticks_after_boot / clock_ticks_per_s;
|
||||
time_after_boot.tv_usec = (ticks_after_boot % clock_ticks_per_s) *
|
||||
(static_cast<long>(1E6) / clock_ticks_per_s);
|
||||
|
||||
timespec uptime;
|
||||
if (clock_gettime(CLOCK_BOOTTIME, &uptime) != 0) {
|
||||
PLOG(ERROR) << "clock_gettime";
|
||||
return false;
|
||||
}
|
||||
|
||||
timespec current_time;
|
||||
if (clock_gettime(CLOCK_REALTIME, ¤t_time) != 0) {
|
||||
PLOG(ERROR) << "clock_gettime";
|
||||
return false;
|
||||
}
|
||||
|
||||
timespec boot_time_ts;
|
||||
SubtractTimespec(current_time, uptime, &boot_time_ts);
|
||||
timeval boot_time_tv;
|
||||
TimespecToTimeval(boot_time_ts, &boot_time_tv);
|
||||
timeradd(&boot_time_tv, &time_after_boot, start_time);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProcStatReader::ReadFile(std::string* contents) const {
|
||||
char path[32];
|
||||
snprintf(path, arraysize(path), "/proc/%d/stat", tid_);
|
||||
if (!LoggingReadEntireFile(base::FilePath(path), contents)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
60
util/linux/proc_stat_reader.h
Normal file
60
util/linux/proc_stat_reader.h
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright 2017 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CRASHPAD_UTIL_LINUX_PROC_STAT_READER_H_
|
||||
#define CRASHPAD_UTIL_LINUX_PROC_STAT_READER_H_
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "util/misc/initialization_state_dcheck.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
//! \brief Reads the /proc/[pid]/stat file for a thread.
|
||||
class ProcStatReader {
|
||||
public:
|
||||
ProcStatReader();
|
||||
~ProcStatReader();
|
||||
|
||||
//! \brief Initializes the reader.
|
||||
//!
|
||||
//! This method must be successfully called before calling any other.
|
||||
//!
|
||||
//! \param[in] tid The thread ID to read the stat file for.
|
||||
bool Initialize(pid_t tid);
|
||||
|
||||
//! \brief Determines the target thread’s start time.
|
||||
//!
|
||||
//! \param[out] start_time The time that the thread started.
|
||||
//!
|
||||
//! \return `true` on success, with \a start_time set. Otherwise, `false` with
|
||||
//! a message logged.
|
||||
bool StartTime(timeval* start_time) const;
|
||||
|
||||
private:
|
||||
bool ReadFile(std::string* contents) const;
|
||||
|
||||
pid_t tid_;
|
||||
InitializationStateDcheck initialized_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ProcStatReader);
|
||||
};
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_UTIL_LINUX_PROC_STAT_READER_H_
|
85
util/linux/proc_stat_reader_test.cc
Normal file
85
util/linux/proc_stat_reader_test.cc
Normal file
@ -0,0 +1,85 @@
|
||||
// Copyright 2017 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "util/linux/proc_stat_reader.h"
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "util/thread/thread.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
TEST(ProcStatReader, Basic) {
|
||||
ProcStatReader stat;
|
||||
ASSERT_TRUE(stat.Initialize(getpid()));
|
||||
|
||||
timeval start_time;
|
||||
ASSERT_TRUE(stat.StartTime(&start_time));
|
||||
|
||||
time_t now;
|
||||
time(&now);
|
||||
EXPECT_LE(start_time.tv_sec, now);
|
||||
}
|
||||
|
||||
pid_t gettid() {
|
||||
return syscall(SYS_gettid);
|
||||
}
|
||||
|
||||
void GetStartTime(timeval* start_time) {
|
||||
ProcStatReader stat;
|
||||
ASSERT_TRUE(stat.Initialize(gettid()));
|
||||
ASSERT_TRUE(stat.StartTime(start_time));
|
||||
}
|
||||
|
||||
class StatTimeThread : public Thread {
|
||||
public:
|
||||
StatTimeThread(timeval* start_time) : start_time_(start_time) {}
|
||||
|
||||
private:
|
||||
void ThreadMain() override { GetStartTime(start_time_); }
|
||||
timeval* start_time_;
|
||||
};
|
||||
|
||||
TEST(ProcStatReader, Threads) {
|
||||
timeval main_time;
|
||||
ASSERT_NO_FATAL_FAILURE(GetStartTime(&main_time));
|
||||
|
||||
timeval thread_time;
|
||||
StatTimeThread thread(&thread_time);
|
||||
thread.Start();
|
||||
ASSERT_NO_FATAL_FAILURE(thread.Join());
|
||||
|
||||
EXPECT_PRED4(
|
||||
[](time_t main_sec,
|
||||
suseconds_t main_usec,
|
||||
time_t thread_sec,
|
||||
suseconds_t thread_usec) {
|
||||
return (thread_sec > main_sec) ||
|
||||
(thread_sec == main_sec && thread_usec > main_usec);
|
||||
},
|
||||
main_time.tv_sec,
|
||||
main_time.tv_usec,
|
||||
thread_time.tv_sec,
|
||||
thread_time.tv_usec);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
75
util/misc/lexing.cc
Normal file
75
util/misc/lexing.cc
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright 2017 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "util/misc/lexing.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
namespace {
|
||||
|
||||
#define MAKE_ADAPTER(type, function) \
|
||||
bool ConvertStringToNumber(const base::StringPiece& input, type* value) { \
|
||||
return function(input, value); \
|
||||
}
|
||||
MAKE_ADAPTER(int, base::StringToInt);
|
||||
MAKE_ADAPTER(unsigned int, base::StringToUint);
|
||||
MAKE_ADAPTER(int64_t, base::StringToInt64);
|
||||
MAKE_ADAPTER(uint64_t, base::StringToUint64);
|
||||
#undef MAKE_ADAPTER
|
||||
|
||||
} // namespace
|
||||
|
||||
bool AdvancePastPrefix(const char** input, const char* pattern) {
|
||||
size_t length = strlen(pattern);
|
||||
if (strncmp(*input, pattern, length) == 0) {
|
||||
*input += length;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool AdvancePastNumber(const char** input, T* value) {
|
||||
size_t length = 0;
|
||||
if (std::numeric_limits<T>::is_signed && **input == '-') {
|
||||
++length;
|
||||
}
|
||||
while (isdigit((*input)[length])) {
|
||||
++length;
|
||||
}
|
||||
bool success =
|
||||
ConvertStringToNumber(base::StringPiece(*input, length), value);
|
||||
if (success) {
|
||||
*input += length;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template bool AdvancePastNumber(const char** input, int* value);
|
||||
template bool AdvancePastNumber(const char** input, unsigned int* value);
|
||||
template bool AdvancePastNumber(const char** input, int64_t* value);
|
||||
template bool AdvancePastNumber(const char** input, uint64_t* value);
|
||||
|
||||
} // namespace crashpad
|
44
util/misc/lexing.h
Normal file
44
util/misc/lexing.h
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2017 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CRASHPAD_UTIL_MISC_LEXING_H_
|
||||
#define CRASHPAD_UTIL_MISC_LEXING_H_
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
//! \brief Match a pattern at the start of a char string.
|
||||
//!
|
||||
//! \param[in,out] input A pointer to the char string to match against. \a input
|
||||
//! is advanced past the matched pattern if it is found.
|
||||
//! \param[in] pattern The pattern to match at the start of \input.
|
||||
//! \return `true` if the pattern is matched exactly and \input is advanced,
|
||||
//! otherwise `false`.
|
||||
bool AdvancePastPrefix(const char** input, const char* pattern);
|
||||
|
||||
//! \brief Convert a prefix of a char string to a numeric value.
|
||||
//!
|
||||
//! Valid values are positive or negative decimal numbers, matching the regular
|
||||
//! expression "-?\d+", and within the limits of T.
|
||||
//!
|
||||
//! \param[in,out] input A pointer to the char string to match against. \a input
|
||||
//! is advanced past the number if one is found.
|
||||
//! \param[out] value The converted number, if one is found.
|
||||
//! \return `true` if a number is found at the start of \a input and \a input is
|
||||
//! advanced, otherwise `false`.
|
||||
template <typename T>
|
||||
bool AdvancePastNumber(const char** input, T* value);
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_UTIL_MISC_LEXING_H
|
@ -14,84 +14,18 @@
|
||||
|
||||
#include "util/posix/process_info.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/scoped_file.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/posix/eintr_wrapper.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "util/file/delimited_file_reader.h"
|
||||
#include "util/file/file_io.h"
|
||||
#include "util/file/file_reader.h"
|
||||
#include "util/linux/proc_stat_reader.h"
|
||||
#include "util/linux/thread_info.h"
|
||||
#include "util/misc/lexing.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
namespace {
|
||||
|
||||
// If the string |pattern| is matched exactly at the start of |input|, advance
|
||||
// |input| past |pattern| and return true.
|
||||
bool AdvancePastPrefix(const char** input, const char* pattern) {
|
||||
size_t length = strlen(pattern);
|
||||
if (strncmp(*input, pattern, length) == 0) {
|
||||
*input += length;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#define MAKE_ADAPTER(type, function) \
|
||||
bool ConvertStringToNumber(const base::StringPiece& input, type* value) { \
|
||||
return function(input, value); \
|
||||
}
|
||||
MAKE_ADAPTER(int, base::StringToInt)
|
||||
MAKE_ADAPTER(unsigned int, base::StringToUint)
|
||||
MAKE_ADAPTER(uint64_t, base::StringToUint64)
|
||||
#undef MAKE_ADAPTER
|
||||
|
||||
// Attempt to convert a prefix of |input| to numeric type T. On success, set
|
||||
// |value| to the number, advance |input| past the number, and return true.
|
||||
template <typename T>
|
||||
bool AdvancePastNumber(const char** input, T* value) {
|
||||
size_t length = 0;
|
||||
if (std::numeric_limits<T>::is_signed && **input == '-') {
|
||||
++length;
|
||||
}
|
||||
while (isdigit((*input)[length])) {
|
||||
++length;
|
||||
}
|
||||
bool success = ConvertStringToNumber(base::StringPiece(*input, length),
|
||||
value);
|
||||
if (success) {
|
||||
*input += length;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SubtractTimespec(const timespec& t1, const timespec& t2,
|
||||
timespec* result) {
|
||||
result->tv_sec = t1.tv_sec - t2.tv_sec;
|
||||
result->tv_nsec = t1.tv_nsec - t2.tv_nsec;
|
||||
if (result->tv_nsec < 0) {
|
||||
result->tv_sec -= 1;
|
||||
result->tv_nsec += static_cast<long>(1E9);
|
||||
}
|
||||
}
|
||||
|
||||
void TimespecToTimeval(const timespec& ts, timeval* tv) {
|
||||
tv->tv_sec = ts.tv_sec;
|
||||
tv->tv_usec = ts.tv_nsec / 1000;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ProcessInfo::ProcessInfo()
|
||||
: supplementary_groups_(),
|
||||
start_time_(),
|
||||
@ -324,74 +258,13 @@ bool ProcessInfo::StartTime(timeval* start_time) const {
|
||||
|
||||
if (start_time_initialized_.is_uninitialized()) {
|
||||
start_time_initialized_.set_invalid();
|
||||
|
||||
char path[32];
|
||||
snprintf(path, sizeof(path), "/proc/%d/stat", pid_);
|
||||
std::string stat_contents;
|
||||
if (!LoggingReadEntireFile(base::FilePath(path), &stat_contents)) {
|
||||
ProcStatReader reader;
|
||||
if (!reader.Initialize(pid_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The process start time is the 22nd column.
|
||||
// The second column is the executable name in parentheses.
|
||||
// The executable name may have parentheses itself, so find the end of the
|
||||
// second column by working backwards to find the last closing parens and
|
||||
// then count forward to the 22nd column.
|
||||
size_t stat_pos = stat_contents.rfind(')');
|
||||
if (stat_pos == std::string::npos) {
|
||||
LOG(ERROR) << "format error";
|
||||
if (!reader.StartTime(&start_time_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int index = 1; index < 21; ++index) {
|
||||
stat_pos = stat_contents.find(' ', stat_pos);
|
||||
if (stat_pos == std::string::npos) {
|
||||
break;
|
||||
}
|
||||
++stat_pos;
|
||||
}
|
||||
if (stat_pos >= stat_contents.size()) {
|
||||
LOG(ERROR) << "format error";
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* ticks_ptr = &stat_contents[stat_pos];
|
||||
|
||||
// start time is in jiffies instead of clock ticks pre 2.6.
|
||||
uint64_t ticks_after_boot;
|
||||
if (!AdvancePastNumber<uint64_t>(&ticks_ptr, &ticks_after_boot)) {
|
||||
LOG(ERROR) << "format error";
|
||||
return false;
|
||||
}
|
||||
long clock_ticks_per_s = sysconf(_SC_CLK_TCK);
|
||||
if (clock_ticks_per_s <= 0) {
|
||||
PLOG(ERROR) << "sysconf";
|
||||
return false;
|
||||
}
|
||||
timeval time_after_boot;
|
||||
time_after_boot.tv_sec = ticks_after_boot / clock_ticks_per_s;
|
||||
time_after_boot.tv_usec =
|
||||
(ticks_after_boot % clock_ticks_per_s) *
|
||||
(static_cast<long>(1E6) / clock_ticks_per_s);
|
||||
|
||||
timespec uptime;
|
||||
if (clock_gettime(CLOCK_BOOTTIME, &uptime) != 0) {
|
||||
PLOG(ERROR) << "clock_gettime";
|
||||
return false;
|
||||
}
|
||||
|
||||
timespec current_time;
|
||||
if (clock_gettime(CLOCK_REALTIME, ¤t_time) != 0) {
|
||||
PLOG(ERROR) << "clock_gettime";
|
||||
return false;
|
||||
}
|
||||
|
||||
timespec boot_time_ts;
|
||||
SubtractTimespec(current_time, uptime, &boot_time_ts);
|
||||
timeval boot_time_tv;
|
||||
TimespecToTimeval(boot_time_ts, &boot_time_tv);
|
||||
timeradd(&boot_time_tv, &time_after_boot, &start_time_);
|
||||
|
||||
start_time_initialized_.set_valid();
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,8 @@
|
||||
'linux/thread_info.h',
|
||||
'linux/scoped_ptrace_attach.cc',
|
||||
'linux/scoped_ptrace_attach.h',
|
||||
'linux/proc_stat_reader.cc',
|
||||
'linux/proc_stat_reader.h',
|
||||
'mac/checked_mach_address_range.h',
|
||||
'mac/launchd.h',
|
||||
'mac/launchd.mm',
|
||||
@ -112,6 +114,8 @@
|
||||
'misc/initialization_state.h',
|
||||
'misc/initialization_state_dcheck.cc',
|
||||
'misc/initialization_state_dcheck.h',
|
||||
'misc/lexing.cc',
|
||||
'misc/lexing.h',
|
||||
'misc/metrics.cc',
|
||||
'misc/metrics.h',
|
||||
'misc/paths.h',
|
||||
|
@ -43,6 +43,7 @@
|
||||
'linux/memory_map_test.cc',
|
||||
'linux/process_memory_range_test.cc',
|
||||
'linux/process_memory_test.cc',
|
||||
'linux/proc_stat_reader_test.cc',
|
||||
'linux/thread_info_test.cc',
|
||||
'linux/scoped_ptrace_attach_test.cc',
|
||||
'mac/launchd_test.mm',
|
||||
|
Loading…
x
Reference in New Issue
Block a user