| Index: base/debug/activity_tracker.cc
|
| diff --git a/base/debug/activity_tracker.cc b/base/debug/activity_tracker.cc
|
| index 6b492f0e154ae9078db31b59b831e9688e2def1b..e763413218009adcf780a3ea18d727e71005ccef 100644
|
| --- a/base/debug/activity_tracker.cc
|
| +++ b/base/debug/activity_tracker.cc
|
| @@ -67,7 +67,7 @@ union ThreadRef {
|
| #endif
|
| };
|
|
|
| -// Get the next non-zero identifier. It is only unique within a process.
|
| +// Gets the next non-zero identifier. It is only unique within a process.
|
| uint32_t GetNextDataId() {
|
| uint32_t id;
|
| while ((id = g_next_id.GetNext()) == 0)
|
| @@ -75,6 +75,16 @@ uint32_t GetNextDataId() {
|
| return id;
|
| }
|
|
|
| +// Gets the current process-id, either from the GlobalActivityTracker if it
|
| +// exists (where the PID can be defined for testing) or from the system if
|
| +// there isn't such.
|
| +int64_t GetProcessId() {
|
| + GlobalActivityTracker* global = GlobalActivityTracker::Get();
|
| + if (global)
|
| + return global->process_id();
|
| + return GetCurrentProcId();
|
| +}
|
| +
|
| // Finds and reuses a specific allocation or creates a new one.
|
| PersistentMemoryAllocator::Reference AllocateFrom(
|
| PersistentMemoryAllocator* allocator,
|
| @@ -114,15 +124,15 @@ Time WallTimeFromTickTime(int64_t ticks_start, int64_t ticks, Time time_start) {
|
| OwningProcess::OwningProcess() {}
|
| OwningProcess::~OwningProcess() {}
|
|
|
| -void OwningProcess::Release_Initialize() {
|
| +void OwningProcess::Release_Initialize(int64_t pid) {
|
| uint32_t old_id = data_id.load(std::memory_order_acquire);
|
| DCHECK_EQ(0U, old_id);
|
| - process_id = GetCurrentProcId();
|
| + process_id = pid != 0 ? pid : GetProcessId();
|
| create_stamp = Time::Now().ToInternalValue();
|
| data_id.store(GetNextDataId(), std::memory_order_release);
|
| }
|
|
|
| -void OwningProcess::SetOwningProcessIdForTesting(ProcessId pid, int64_t stamp) {
|
| +void OwningProcess::SetOwningProcessIdForTesting(int64_t pid, int64_t stamp) {
|
| DCHECK_NE(0U, data_id);
|
| process_id = pid;
|
| create_stamp = stamp;
|
| @@ -130,14 +140,14 @@ void OwningProcess::SetOwningProcessIdForTesting(ProcessId pid, int64_t stamp) {
|
|
|
| // static
|
| bool OwningProcess::GetOwningProcessId(const void* memory,
|
| - ProcessId* out_id,
|
| + int64_t* out_id,
|
| int64_t* out_stamp) {
|
| const OwningProcess* info = reinterpret_cast<const OwningProcess*>(memory);
|
| uint32_t id = info->data_id.load(std::memory_order_acquire);
|
| if (id == 0)
|
| return false;
|
|
|
| - *out_id = static_cast<ProcessId>(info->process_id);
|
| + *out_id = info->process_id;
|
| *out_stamp = info->create_stamp;
|
| return id == info->data_id.load(std::memory_order_seq_cst);
|
| }
|
| @@ -322,12 +332,15 @@ ActivityUserData::MemoryHeader::~MemoryHeader() {}
|
| ActivityUserData::FieldHeader::FieldHeader() {}
|
| ActivityUserData::FieldHeader::~FieldHeader() {}
|
|
|
| -ActivityUserData::ActivityUserData() : ActivityUserData(nullptr, 0) {}
|
| +ActivityUserData::ActivityUserData() : ActivityUserData(nullptr, 0, -1) {}
|
|
|
| -ActivityUserData::ActivityUserData(void* memory, size_t size)
|
| +ActivityUserData::ActivityUserData(void* memory, size_t size, int64_t pid)
|
| : memory_(reinterpret_cast<char*>(memory)),
|
| available_(RoundDownToAlignment(size, kMemoryAlignment)),
|
| - header_(reinterpret_cast<MemoryHeader*>(memory)) {
|
| + header_(reinterpret_cast<MemoryHeader*>(memory)),
|
| + orig_data_id(0),
|
| + orig_process_id(0),
|
| + orig_create_stamp(0) {
|
| // It's possible that no user data is being stored.
|
| if (!memory_)
|
| return;
|
| @@ -335,10 +348,16 @@ ActivityUserData::ActivityUserData(void* memory, size_t size)
|
| static_assert(0 == sizeof(MemoryHeader) % kMemoryAlignment, "invalid header");
|
| DCHECK_LT(sizeof(MemoryHeader), available_);
|
| if (header_->owner.data_id.load(std::memory_order_acquire) == 0)
|
| - header_->owner.Release_Initialize();
|
| + header_->owner.Release_Initialize(pid);
|
| memory_ += sizeof(MemoryHeader);
|
| available_ -= sizeof(MemoryHeader);
|
|
|
| + // Make a copy of identifying information for later comparison.
|
| + *const_cast<uint32_t*>(&orig_data_id) =
|
| + header_->owner.data_id.load(std::memory_order_acquire);
|
| + *const_cast<int64_t*>(&orig_process_id) = header_->owner.process_id;
|
| + *const_cast<int64_t*>(&orig_create_stamp) = header_->owner.create_stamp;
|
| +
|
| // If there is already data present, load that. This allows the same class
|
| // to be used for analysis through snapshots.
|
| ImportExistingData();
|
| @@ -354,18 +373,18 @@ bool ActivityUserData::CreateSnapshot(Snapshot* output_snapshot) const {
|
| // class that is adding records.
|
| ImportExistingData();
|
|
|
| + // Add all the values to the snapshot.
|
| for (const auto& entry : values_) {
|
| TypedValue value;
|
| + const size_t size = entry.second.size_ptr->load(std::memory_order_acquire);
|
| value.type_ = entry.second.type;
|
| - DCHECK_GE(entry.second.extent,
|
| - entry.second.size_ptr->load(std::memory_order_relaxed));
|
| + DCHECK_GE(entry.second.extent, size);
|
|
|
| switch (entry.second.type) {
|
| case RAW_VALUE:
|
| case STRING_VALUE:
|
| value.long_value_ =
|
| - std::string(reinterpret_cast<char*>(entry.second.memory),
|
| - entry.second.size_ptr->load(std::memory_order_relaxed));
|
| + std::string(reinterpret_cast<char*>(entry.second.memory), size);
|
| break;
|
| case RAW_VALUE_REFERENCE:
|
| case STRING_VALUE_REFERENCE: {
|
| @@ -391,6 +410,16 @@ bool ActivityUserData::CreateSnapshot(Snapshot* output_snapshot) const {
|
| DCHECK(inserted.second); // True if inserted, false if existed.
|
| }
|
|
|
| + // Another import attempt will validate that the underlying memory has not
|
| + // been reused for another purpose. Entries added since the first import
|
| + // will be ignored here but will be returned if another snapshot is created.
|
| + ImportExistingData();
|
| + if (!memory_) {
|
| + output_snapshot->clear();
|
| + return false;
|
| + }
|
| +
|
| + // Successful snapshot.
|
| return true;
|
| }
|
|
|
| @@ -400,7 +429,7 @@ const void* ActivityUserData::GetBaseAddress() const {
|
| return header_;
|
| }
|
|
|
| -void ActivityUserData::SetOwningProcessIdForTesting(ProcessId pid,
|
| +void ActivityUserData::SetOwningProcessIdForTesting(int64_t pid,
|
| int64_t stamp) {
|
| if (!header_)
|
| return;
|
| @@ -409,7 +438,7 @@ void ActivityUserData::SetOwningProcessIdForTesting(ProcessId pid,
|
|
|
| // static
|
| bool ActivityUserData::GetOwningProcessId(const void* memory,
|
| - ProcessId* out_id,
|
| + int64_t* out_id,
|
| int64_t* out_stamp) {
|
| const MemoryHeader* header = reinterpret_cast<const MemoryHeader*>(memory);
|
| return OwningProcess::GetOwningProcessId(&header->owner, out_id, out_stamp);
|
| @@ -524,6 +553,10 @@ void ActivityUserData::SetReference(StringPiece name,
|
| }
|
|
|
| void ActivityUserData::ImportExistingData() const {
|
| + // It's possible that no user data is being stored.
|
| + if (!memory_)
|
| + return;
|
| +
|
| while (available_ > sizeof(FieldHeader)) {
|
| FieldHeader* header = reinterpret_cast<FieldHeader*>(memory_);
|
| ValueType type =
|
| @@ -555,6 +588,14 @@ void ActivityUserData::ImportExistingData() const {
|
| memory_ += header->record_size;
|
| available_ -= header->record_size;
|
| }
|
| +
|
| + // Check if memory has been completely reused.
|
| + if (header_->owner.data_id.load(std::memory_order_acquire) != orig_data_id ||
|
| + header_->owner.process_id != orig_process_id ||
|
| + header_->owner.create_stamp != orig_create_stamp) {
|
| + memory_ = nullptr;
|
| + values_.clear();
|
| + }
|
| }
|
|
|
| // This information is kept for every thread that is tracked. It is filled
|
| @@ -895,6 +936,7 @@ bool ThreadActivityTracker::CreateSnapshot(Snapshot* output_snapshot) const {
|
| // structure are valid (at least at the current moment in time).
|
| const uint32_t starting_id =
|
| header_->owner.data_id.load(std::memory_order_acquire);
|
| + const int64_t starting_create_stamp = header_->owner.create_stamp;
|
| const int64_t starting_process_id = header_->owner.process_id;
|
| const int64_t starting_thread_id = header_->thread_ref.as_id;
|
|
|
| @@ -932,6 +974,7 @@ bool ThreadActivityTracker::CreateSnapshot(Snapshot* output_snapshot) const {
|
| // Get the general thread information.
|
| output_snapshot->thread_name =
|
| std::string(header_->thread_name, sizeof(header_->thread_name) - 1);
|
| + output_snapshot->create_stamp = header_->owner.create_stamp;
|
| output_snapshot->thread_id = header_->thread_ref.as_id;
|
| output_snapshot->process_id = header_->owner.process_id;
|
|
|
| @@ -944,6 +987,7 @@ bool ThreadActivityTracker::CreateSnapshot(Snapshot* output_snapshot) const {
|
| // If the data ID has changed then the tracker has exited and the memory
|
| // reused by a new one. Try again.
|
| if (header_->owner.data_id.load(std::memory_order_seq_cst) != starting_id ||
|
| + output_snapshot->create_stamp != starting_create_stamp ||
|
| output_snapshot->process_id != starting_process_id ||
|
| output_snapshot->thread_id != starting_thread_id) {
|
| continue;
|
| @@ -981,14 +1025,14 @@ const void* ThreadActivityTracker::GetBaseAddress() {
|
| return header_;
|
| }
|
|
|
| -void ThreadActivityTracker::SetOwningProcessIdForTesting(ProcessId pid,
|
| +void ThreadActivityTracker::SetOwningProcessIdForTesting(int64_t pid,
|
| int64_t stamp) {
|
| header_->owner.SetOwningProcessIdForTesting(pid, stamp);
|
| }
|
|
|
| // static
|
| bool ThreadActivityTracker::GetOwningProcessId(const void* memory,
|
| - ProcessId* out_id,
|
| + int64_t* out_id,
|
| int64_t* out_stamp) {
|
| const Header* header = reinterpret_cast<const Header*>(memory);
|
| return OwningProcess::GetOwningProcessId(&header->owner, out_id, out_stamp);
|
| @@ -1179,8 +1223,9 @@ ActivityUserData& GlobalActivityTracker::ScopedThreadActivity::user_data() {
|
| }
|
|
|
| GlobalActivityTracker::ThreadSafeUserData::ThreadSafeUserData(void* memory,
|
| - size_t size)
|
| - : ActivityUserData(memory, size) {}
|
| + size_t size,
|
| + int64_t pid)
|
| + : ActivityUserData(memory, size, pid) {}
|
|
|
| GlobalActivityTracker::ThreadSafeUserData::~ThreadSafeUserData() {}
|
|
|
| @@ -1210,10 +1255,11 @@ GlobalActivityTracker::ManagedActivityTracker::~ManagedActivityTracker() {
|
|
|
| void GlobalActivityTracker::CreateWithAllocator(
|
| std::unique_ptr<PersistentMemoryAllocator> allocator,
|
| - int stack_depth) {
|
| + int stack_depth,
|
| + int64_t process_id) {
|
| // There's no need to do anything with the result. It is self-managing.
|
| GlobalActivityTracker* global_tracker =
|
| - new GlobalActivityTracker(std::move(allocator), stack_depth);
|
| + new GlobalActivityTracker(std::move(allocator), stack_depth, process_id);
|
| // Create a tracker for this thread since it is known.
|
| global_tracker->CreateTrackerForCurrentThread();
|
| }
|
| @@ -1239,7 +1285,7 @@ void GlobalActivityTracker::CreateWithFile(const FilePath& file_path,
|
| DCHECK(success);
|
| CreateWithAllocator(MakeUnique<FilePersistentMemoryAllocator>(
|
| std::move(mapped_file), size, id, name, false),
|
| - stack_depth);
|
| + stack_depth, 0);
|
| }
|
| #endif // !defined(OS_NACL)
|
|
|
| @@ -1247,11 +1293,32 @@ void GlobalActivityTracker::CreateWithFile(const FilePath& file_path,
|
| void GlobalActivityTracker::CreateWithLocalMemory(size_t size,
|
| uint64_t id,
|
| StringPiece name,
|
| - int stack_depth) {
|
| + int stack_depth,
|
| + int64_t process_id) {
|
| CreateWithAllocator(
|
| - MakeUnique<LocalPersistentMemoryAllocator>(size, id, name), stack_depth);
|
| + MakeUnique<LocalPersistentMemoryAllocator>(size, id, name), stack_depth,
|
| + process_id);
|
| +}
|
| +
|
| +// static
|
| +void GlobalActivityTracker::SetForTesting(
|
| + std::unique_ptr<GlobalActivityTracker> tracker) {
|
| + CHECK(!subtle::NoBarrier_Load(&g_tracker_));
|
| + subtle::Release_Store(&g_tracker_,
|
| + reinterpret_cast<uintptr_t>(tracker.release()));
|
| }
|
|
|
| +// static
|
| +std::unique_ptr<GlobalActivityTracker>
|
| +GlobalActivityTracker::ReleaseForTesting() {
|
| + GlobalActivityTracker* tracker = Get();
|
| + if (!tracker)
|
| + return nullptr;
|
| +
|
| + subtle::Release_Store(&g_tracker_, 0);
|
| + return WrapUnique(tracker);
|
| +};
|
| +
|
| ThreadActivityTracker* GlobalActivityTracker::CreateTrackerForCurrentThread() {
|
| DCHECK(!this_thread_tracker_.Get());
|
|
|
| @@ -1308,8 +1375,10 @@ ThreadActivityTracker* GlobalActivityTracker::CreateTrackerForCurrentThread() {
|
| void GlobalActivityTracker::ReleaseTrackerForCurrentThreadForTesting() {
|
| ThreadActivityTracker* tracker =
|
| reinterpret_cast<ThreadActivityTracker*>(this_thread_tracker_.Get());
|
| - if (tracker)
|
| + if (tracker) {
|
| + this_thread_tracker_.Set(nullptr);
|
| delete tracker;
|
| + }
|
| }
|
|
|
| void GlobalActivityTracker::SetBackgroundTaskRunner(
|
| @@ -1327,21 +1396,23 @@ void GlobalActivityTracker::SetProcessExitCallback(
|
| void GlobalActivityTracker::RecordProcessLaunch(
|
| ProcessId process_id,
|
| const FilePath::StringType& cmd) {
|
| - DCHECK_NE(GetCurrentProcId(), process_id);
|
| + const int64_t pid = process_id;
|
| + DCHECK_NE(GetProcessId(), pid);
|
| + DCHECK_NE(0, pid);
|
|
|
| base::AutoLock lock(global_tracker_lock_);
|
| - if (base::ContainsKey(known_processes_, process_id)) {
|
| + if (base::ContainsKey(known_processes_, pid)) {
|
| // TODO(bcwhite): Measure this in UMA.
|
| NOTREACHED() << "Process #" << process_id
|
| << " was previously recorded as \"launched\""
|
| << " with no corresponding exit.";
|
| - known_processes_.erase(process_id);
|
| + known_processes_.erase(pid);
|
| }
|
|
|
| #if defined(OS_WIN)
|
| - known_processes_.insert(std::make_pair(process_id, UTF16ToUTF8(cmd)));
|
| + known_processes_.insert(std::make_pair(pid, UTF16ToUTF8(cmd)));
|
| #else
|
| - known_processes_.insert(std::make_pair(process_id, cmd));
|
| + known_processes_.insert(std::make_pair(pid, cmd));
|
| #endif
|
| }
|
|
|
| @@ -1349,25 +1420,27 @@ void GlobalActivityTracker::RecordProcessLaunch(
|
| ProcessId process_id,
|
| const FilePath::StringType& exe,
|
| const FilePath::StringType& args) {
|
| + const int64_t pid = process_id;
|
| if (exe.find(FILE_PATH_LITERAL(" "))) {
|
| - RecordProcessLaunch(process_id,
|
| - FilePath::StringType(FILE_PATH_LITERAL("\"")) + exe +
|
| - FILE_PATH_LITERAL("\" ") + args);
|
| + RecordProcessLaunch(pid, FilePath::StringType(FILE_PATH_LITERAL("\"")) +
|
| + exe + FILE_PATH_LITERAL("\" ") + args);
|
| } else {
|
| - RecordProcessLaunch(process_id, exe + FILE_PATH_LITERAL(' ') + args);
|
| + RecordProcessLaunch(pid, exe + FILE_PATH_LITERAL(' ') + args);
|
| }
|
| }
|
|
|
| void GlobalActivityTracker::RecordProcessExit(ProcessId process_id,
|
| int exit_code) {
|
| - DCHECK_NE(GetCurrentProcId(), process_id);
|
| + const int64_t pid = process_id;
|
| + DCHECK_NE(GetProcessId(), pid);
|
| + DCHECK_NE(0, pid);
|
|
|
| scoped_refptr<TaskRunner> task_runner;
|
| std::string command_line;
|
| {
|
| base::AutoLock lock(global_tracker_lock_);
|
| task_runner = background_task_runner_;
|
| - auto found = known_processes_.find(process_id);
|
| + auto found = known_processes_.find(pid);
|
| if (found != known_processes_.end()) {
|
| command_line = std::move(found->second);
|
| known_processes_.erase(found);
|
| @@ -1385,20 +1458,19 @@ void GlobalActivityTracker::RecordProcessExit(ProcessId process_id,
|
| if (task_runner && !task_runner->RunsTasksOnCurrentThread()) {
|
| task_runner->PostTask(
|
| FROM_HERE,
|
| - Bind(&GlobalActivityTracker::CleanupAfterProcess, Unretained(this),
|
| - process_id, now_stamp, exit_code, Passed(&command_line)));
|
| + Bind(&GlobalActivityTracker::CleanupAfterProcess, Unretained(this), pid,
|
| + now_stamp, exit_code, Passed(&command_line)));
|
| return;
|
| }
|
|
|
| - CleanupAfterProcess(process_id, now_stamp, exit_code,
|
| - std::move(command_line));
|
| + CleanupAfterProcess(pid, now_stamp, exit_code, std::move(command_line));
|
| }
|
|
|
| void GlobalActivityTracker::SetProcessPhase(ProcessPhase phase) {
|
| process_data().SetInt(kProcessPhaseDataKey, phase);
|
| }
|
|
|
| -void GlobalActivityTracker::CleanupAfterProcess(ProcessId process_id,
|
| +void GlobalActivityTracker::CleanupAfterProcess(int64_t process_id,
|
| int64_t exit_stamp,
|
| int exit_code,
|
| std::string&& command_line) {
|
| @@ -1422,7 +1494,7 @@ void GlobalActivityTracker::CleanupAfterProcess(ProcessId process_id,
|
| while ((ref = iter.GetNextOfType(kTypeIdProcessDataRecord)) != 0) {
|
| const void* memory = allocator_->GetAsArray<char>(
|
| ref, kTypeIdProcessDataRecord, PersistentMemoryAllocator::kSizeAny);
|
| - ProcessId found_id;
|
| + int64_t found_id;
|
| int64_t create_stamp;
|
| if (ActivityUserData::GetOwningProcessId(memory, &found_id,
|
| &create_stamp)) {
|
| @@ -1459,7 +1531,7 @@ void GlobalActivityTracker::CleanupAfterProcess(ProcessId process_id,
|
| case ModuleInfoRecord::kPersistentTypeId: {
|
| const void* memory = allocator_->GetAsArray<char>(
|
| ref, type, PersistentMemoryAllocator::kSizeAny);
|
| - ProcessId found_id;
|
| + int64_t found_id;
|
| int64_t create_stamp;
|
|
|
| // By convention, the OwningProcess structure is always the first
|
| @@ -1527,9 +1599,11 @@ void GlobalActivityTracker::RecordFieldTrial(const std::string& trial_name,
|
|
|
| GlobalActivityTracker::GlobalActivityTracker(
|
| std::unique_ptr<PersistentMemoryAllocator> allocator,
|
| - int stack_depth)
|
| + int stack_depth,
|
| + int64_t process_id)
|
| : allocator_(std::move(allocator)),
|
| stack_memory_size_(ThreadActivityTracker::SizeForStackDepth(stack_depth)),
|
| + process_id_(process_id == 0 ? GetCurrentProcId() : process_id),
|
| this_thread_tracker_(&OnTLSDestroy),
|
| thread_tracker_count_(0),
|
| thread_tracker_allocator_(allocator_.get(),
|
| @@ -1551,16 +1625,16 @@ GlobalActivityTracker::GlobalActivityTracker(
|
| kTypeIdProcessDataRecord),
|
| kTypeIdProcessDataRecord,
|
| kProcessDataSize),
|
| - kProcessDataSize),
|
| + kProcessDataSize,
|
| + process_id_),
|
| global_data_(
|
| allocator_->GetAsArray<char>(
|
| allocator_->Allocate(kGlobalDataSize, kTypeIdGlobalDataRecord),
|
| kTypeIdGlobalDataRecord,
|
| kGlobalDataSize),
|
| - kGlobalDataSize) {
|
| - // Ensure the passed memory is valid and empty (iterator finds nothing).
|
| - uint32_t type;
|
| - DCHECK(!PersistentMemoryAllocator::Iterator(allocator_.get()).GetNext(&type));
|
| + kGlobalDataSize,
|
| + process_id_) {
|
| + DCHECK_NE(0, process_id_);
|
|
|
| // Ensure that there is no other global object and then make this one such.
|
| DCHECK(!g_tracker_);
|
| @@ -1583,7 +1657,7 @@ GlobalActivityTracker::GlobalActivityTracker(
|
| }
|
|
|
| GlobalActivityTracker::~GlobalActivityTracker() {
|
| - DCHECK_EQ(Get(), this);
|
| + DCHECK(Get() == nullptr || Get() == this);
|
| DCHECK_EQ(0, thread_tracker_count_.load(std::memory_order_relaxed));
|
| subtle::Release_Store(&g_tracker_, 0);
|
| }
|
|
|