diff options
Diffstat (limited to 'base/debug/activity_tracker.cc')
-rw-r--r-- | base/debug/activity_tracker.cc | 181 |
1 files changed, 130 insertions, 51 deletions
diff --git a/base/debug/activity_tracker.cc b/base/debug/activity_tracker.cc index 6b492f0e15..5081c1c9d2 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,37 @@ 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; + + // Thread trackers assume that the global tracker is present for some + // operations so ensure that there aren't any. + tracker->ReleaseTrackerForCurrentThreadForTesting(); + DCHECK_EQ(0, tracker->thread_tracker_count_.load(std::memory_order_relaxed)); + + subtle::Release_Store(&g_tracker_, 0); + return WrapUnique(tracker); +}; + ThreadActivityTracker* GlobalActivityTracker::CreateTrackerForCurrentThread() { DCHECK(!this_thread_tracker_.Get()); @@ -1308,8 +1380,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 +1401,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 +1425,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 +1463,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 +1499,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 +1536,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 +1604,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 +1630,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 +1662,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); } |