diff options
author | Hidehiko Abe <hidehiko@google.com> | 2018-02-21 03:06:26 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2018-02-21 03:06:26 +0000 |
commit | d3a70e1555860b4c5b7f991eb549cd757300909e (patch) | |
tree | b5545667cc754e2b0745fb59dd891d65d30afaeb /base/debug | |
parent | 97da0eb3ad812d16ac608f39ed3e2f38e2400fc5 (diff) | |
parent | 5dbf0c2ab3ce8ba3300639cb2a50515fe913be7f (diff) | |
download | libchrome-d3a70e1555860b4c5b7f991eb549cd757300909e.tar.gz |
Re-uprev to r462023. am: f810b5921d am: 81c2b1d888
am: 5dbf0c2ab3
Change-Id: Iffb77836212172c38eeb660f550d7b1724a2910c
Diffstat (limited to 'base/debug')
-rw-r--r-- | base/debug/activity_tracker.cc | 181 | ||||
-rw-r--r-- | base/debug/activity_tracker.h | 75 | ||||
-rw-r--r-- | base/debug/activity_tracker_unittest.cc | 12 |
3 files changed, 192 insertions, 76 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); } diff --git a/base/debug/activity_tracker.h b/base/debug/activity_tracker.h index e6eb197881..c8cf1e972e 100644 --- a/base/debug/activity_tracker.h +++ b/base/debug/activity_tracker.h @@ -67,16 +67,16 @@ struct OwningProcess { // Initializes structure with the current process id and the current time. // These can uniquely identify a process. A unique non-zero data_id will be // set making it possible to tell using atomic reads if the data has changed. - void Release_Initialize(); + void Release_Initialize(int64_t pid = 0); // Explicitly sets the process ID. - void SetOwningProcessIdForTesting(ProcessId pid, int64_t stamp); + void SetOwningProcessIdForTesting(int64_t pid, int64_t stamp); // Gets the associated process ID, in native form, and the creation timestamp // from memory without loading the entire structure for analysis. This will // return false if no valid process ID is available. static bool GetOwningProcessId(const void* memory, - ProcessId* out_id, + int64_t* out_id, int64_t* out_stamp); // SHA1(base::debug::OwningProcess): Increment this if structure changes! @@ -393,7 +393,7 @@ class BASE_EXPORT ActivityUserData { private: friend class ActivityUserData; - ValueType type_; + ValueType type_ = END_OF_VALUES; uint64_t short_value_; // Used to hold copy of numbers, etc. std::string long_value_; // Used to hold copy of raw/string data. StringPiece ref_value_; // Used to hold reference to external data. @@ -404,7 +404,7 @@ class BASE_EXPORT ActivityUserData { // Initialize the object either as a "sink" that just accepts and discards // data or an active one that writes to a given (zeroed) memory block. ActivityUserData(); - ActivityUserData(void* memory, size_t size); + ActivityUserData(void* memory, size_t size, int64_t pid = 0); virtual ~ActivityUserData(); // Gets the unique ID number for this user data. If this changes then the @@ -459,22 +459,22 @@ class BASE_EXPORT ActivityUserData { // Creates a snapshot of the key/value pairs contained within. The returned // data will be fixed, independent of whatever changes afterward. There is - // protection against concurrent modification of the values but no protection - // against a complete overwrite of the contents; the caller must ensure that - // the memory segment is not going to be re-initialized while this runs. + // some protection against concurrent modification. This will return false + // if the data is invalid or if a complete overwrite of the contents is + // detected. bool CreateSnapshot(Snapshot* output_snapshot) const; // Gets the base memory address used for storing data. const void* GetBaseAddress() const; // Explicitly sets the process ID. - void SetOwningProcessIdForTesting(ProcessId pid, int64_t stamp); + void SetOwningProcessIdForTesting(int64_t pid, int64_t stamp); // Gets the associated process ID, in native form, and the creation timestamp // from tracker memory without loading the entire structure for analysis. This // will return false if no valid process ID is available. static bool GetOwningProcessId(const void* memory, - ProcessId* out_id, + int64_t* out_id, int64_t* out_stamp); protected: @@ -533,7 +533,10 @@ class BASE_EXPORT ActivityUserData { size_t size); // Loads any data already in the memory segment. This allows for accessing - // records created previously. + // records created previously. If this detects that the underlying data has + // gone away (cleared by another thread/process), it will invalidate all the + // data in this object and turn it into simple "sink" with no values to + // return. void ImportExistingData() const; // A map of all the values within the memory block, keyed by name for quick @@ -550,6 +553,12 @@ class BASE_EXPORT ActivityUserData { // A pointer to the memory header for this instance. MemoryHeader* const header_; + // These hold values used when initially creating the object. They are + // compared against current header values to check for outside changes. + const uint32_t orig_data_id; + const int64_t orig_process_id; + const int64_t orig_create_stamp; + DISALLOW_COPY_AND_ASSIGN(ActivityUserData); }; @@ -584,6 +593,9 @@ class BASE_EXPORT ThreadActivityTracker { // truncated due to internal length limitations. std::string thread_name; + // The timestamp at which this process was created. + int64_t create_stamp; + // The process and thread IDs. These values have no meaning other than // they uniquely identify a running process and a running thread within // that process. Thread-IDs can be re-used across different processes @@ -704,13 +716,13 @@ class BASE_EXPORT ThreadActivityTracker { const void* GetBaseAddress(); // Explicitly sets the process ID. - void SetOwningProcessIdForTesting(ProcessId pid, int64_t stamp); + void SetOwningProcessIdForTesting(int64_t pid, int64_t stamp); // Gets the associated process ID, in native form, and the creation timestamp // from tracker memory without loading the entire structure for analysis. This // will return false if no valid process ID is available. static bool GetOwningProcessId(const void* memory, - ProcessId* out_id, + int64_t* out_id, int64_t* out_stamp); // Calculates the memory size required for a given stack depth, including @@ -857,9 +869,12 @@ class BASE_EXPORT GlobalActivityTracker { // Creates a global tracker using a given persistent-memory |allocator| and // providing the given |stack_depth| to each thread tracker it manages. The // created object is activated so tracking will begin immediately upon return. + // The |process_id| can be zero to get it from the OS but is taken for testing + // purposes. static void CreateWithAllocator( std::unique_ptr<PersistentMemoryAllocator> allocator, - int stack_depth); + int stack_depth, + int64_t process_id); #if !defined(OS_NACL) // Like above but internally creates an allocator around a disk file with @@ -874,11 +889,13 @@ class BASE_EXPORT GlobalActivityTracker { #endif // !defined(OS_NACL) // Like above but internally creates an allocator using local heap memory of - // the specified size. This is used primarily for unit tests. + // the specified size. This is used primarily for unit tests. The |process_id| + // can be zero to get it from the OS but is taken for testing purposes. static void CreateWithLocalMemory(size_t size, uint64_t id, StringPiece name, - int stack_depth); + int stack_depth, + int64_t process_id); // Gets the global activity-tracker or null if none exists. static GlobalActivityTracker* Get() { @@ -886,6 +903,15 @@ class BASE_EXPORT GlobalActivityTracker { subtle::Acquire_Load(&g_tracker_)); } + // Sets the global activity-tracker for testing purposes. + static void SetForTesting(std::unique_ptr<GlobalActivityTracker> tracker); + + // This access to the persistent allocator is only for testing; it extracts + // the global tracker completely. All tracked threads must exit before + // calling this. Tracking for the current thread will be automatically + // stopped. + static std::unique_ptr<GlobalActivityTracker> ReleaseForTesting(); + // Convenience method for determining if a global tracker is active. static bool IsEnabled() { return Get() != nullptr; } @@ -998,6 +1024,10 @@ class BASE_EXPORT GlobalActivityTracker { code); } + // Gets the process ID used for tracking. This is typically the same as what + // the OS thinks is the current process but can be overridden for testing. + int64_t process_id() { return process_id_; }; + // Accesses the process data record for storing arbitrary key/value pairs. // Updates to this are thread-safe. ActivityUserData& process_data() { return process_data_; } @@ -1024,7 +1054,7 @@ class BASE_EXPORT GlobalActivityTracker { // thread. class ThreadSafeUserData : public ActivityUserData { public: - ThreadSafeUserData(void* memory, size_t size); + ThreadSafeUserData(void* memory, size_t size, int64_t pid = 0); ~ThreadSafeUserData() override; private: @@ -1108,8 +1138,11 @@ class BASE_EXPORT GlobalActivityTracker { // Creates a global tracker using a given persistent-memory |allocator| and // providing the given |stack_depth| to each thread tracker it manages. The // created object is activated so tracking has already started upon return. + // The |process_id| can be zero to get it from the OS but is taken for testing + // purposes. GlobalActivityTracker(std::unique_ptr<PersistentMemoryAllocator> allocator, - int stack_depth); + int stack_depth, + int64_t process_id); // Returns the memory used by an activity-tracker managed by this class. // It is called during the destruction of a ManagedActivityTracker object. @@ -1124,7 +1157,7 @@ class BASE_EXPORT GlobalActivityTracker { static void OnTLSDestroy(void* value); // Does process-exit work. This can be run on any thread. - void CleanupAfterProcess(ProcessId process_id, + void CleanupAfterProcess(int64_t process_id, int64_t exit_stamp, int exit_code, std::string&& command_line); @@ -1137,6 +1170,10 @@ class BASE_EXPORT GlobalActivityTracker { // provide the stack-depth requested during construction. const size_t stack_memory_size_; + // The process-id of the current process. This is kept as a member variable, + // defined during initialization, for testing purposes. + const int64_t process_id_; + // The activity tracker for the currently executing thread. base::ThreadLocalStorage::Slot this_thread_tracker_; diff --git a/base/debug/activity_tracker_unittest.cc b/base/debug/activity_tracker_unittest.cc index 116c13d623..c7efa580e8 100644 --- a/base/debug/activity_tracker_unittest.cc +++ b/base/debug/activity_tracker_unittest.cc @@ -204,7 +204,7 @@ TEST_F(ActivityTrackerTest, PushPopTest) { } TEST_F(ActivityTrackerTest, ScopedTaskTest) { - GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3); + GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); ThreadActivityTracker* tracker = GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread(); @@ -251,7 +251,7 @@ TEST_F(ActivityTrackerTest, ScopedTaskTest) { } TEST_F(ActivityTrackerTest, ExceptionTest) { - GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3); + GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); GlobalActivityTracker* global = GlobalActivityTracker::Get(); ThreadActivityTracker* tracker = @@ -301,7 +301,7 @@ TEST_F(ActivityTrackerTest, CreateWithFileTest) { // GlobalActivityTracker tests below. TEST_F(ActivityTrackerTest, BasicTest) { - GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3); + GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); GlobalActivityTracker* global = GlobalActivityTracker::Get(); // Ensure the data repositories have backing store, indicated by non-zero ID. @@ -364,7 +364,7 @@ class SimpleActivityThread : public SimpleThread { }; TEST_F(ActivityTrackerTest, ThreadDeathTest) { - GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3); + GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread(); const size_t starting_active = GetGlobalActiveTrackerCount(); const size_t starting_inactive = GetGlobalInactiveTrackerCount(); @@ -401,7 +401,7 @@ TEST_F(ActivityTrackerTest, ProcessDeathTest) { // testing interfaces to simulate data created by other processes. const ProcessId other_process_id = GetCurrentProcId() + 1; - GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3); + GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); GlobalActivityTracker* global = GlobalActivityTracker::Get(); ThreadActivityTracker* thread = global->GetOrCreateTrackerForCurrentThread(); @@ -441,7 +441,7 @@ TEST_F(ActivityTrackerTest, ProcessDeathTest) { memcpy(tracker_copy.get(), thread->GetBaseAddress(), tracker_size); // Change the objects to appear to be owned by another process. - ProcessId owning_id; + int64_t owning_id; int64_t stamp; ASSERT_TRUE(ActivityUserData::GetOwningProcessId( global->process_data().GetBaseAddress(), &owning_id, &stamp)); |