summaryrefslogtreecommitdiff
path: root/base/debug
diff options
context:
space:
mode:
authorHidehiko Abe <hidehiko@google.com>2018-02-21 03:06:26 +0000
committerandroid-build-merger <android-build-merger@google.com>2018-02-21 03:06:26 +0000
commitd3a70e1555860b4c5b7f991eb549cd757300909e (patch)
treeb5545667cc754e2b0745fb59dd891d65d30afaeb /base/debug
parent97da0eb3ad812d16ac608f39ed3e2f38e2400fc5 (diff)
parent5dbf0c2ab3ce8ba3300639cb2a50515fe913be7f (diff)
downloadlibchrome-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.cc181
-rw-r--r--base/debug/activity_tracker.h75
-rw-r--r--base/debug/activity_tracker_unittest.cc12
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));