1 // Copyright 2016 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/debug/activity_tracker.h" 6 7 #include <algorithm> 8 #include <limits> 9 #include <utility> 10 11 #include "base/atomic_sequence_num.h" 12 #include "base/debug/stack_trace.h" 13 #include "base/files/file.h" 14 #include "base/files/file_path.h" 15 #include "base/files/memory_mapped_file.h" 16 #include "base/logging.h" 17 #include "base/memory/ptr_util.h" 18 #include "base/metrics/field_trial.h" 19 #include "base/metrics/histogram_macros.h" 20 #include "base/pending_task.h" 21 #include "base/pickle.h" 22 #include "base/process/process.h" 23 #include "base/process/process_handle.h" 24 #include "base/stl_util.h" 25 #include "base/strings/string_util.h" 26 #include "base/strings/utf_string_conversions.h" 27 #include "base/threading/platform_thread.h" 28 #include "build/build_config.h" 29 30 namespace base { 31 namespace debug { 32 33 namespace { 34 35 // The minimum depth a stack should support. 36 const int kMinStackDepth = 2; 37 38 // The amount of memory set aside for holding arbitrary user data (key/value 39 // pairs) globally or associated with ActivityData entries. 40 const size_t kUserDataSize = 1 << 10; // 1 KiB 41 const size_t kProcessDataSize = 4 << 10; // 4 KiB 42 const size_t kMaxUserDataNameLength = 43 static_cast<size_t>(std::numeric_limits<uint8_t>::max()); 44 45 // A constant used to indicate that module information is changing. 46 const uint32_t kModuleInformationChanging = 0x80000000; 47 48 // The key used to record process information. 49 const char kProcessPhaseDataKey[] = "process-phase"; 50 51 // An atomically incrementing number, used to check for recreations of objects 52 // in the same memory space. 53 AtomicSequenceNumber g_next_id; 54 55 // Gets the next non-zero identifier. It is only unique within a process. 56 uint32_t GetNextDataId() { 57 uint32_t id; 58 while ((id = g_next_id.GetNext()) == 0) 59 ; 60 return id; 61 } 62 63 // Gets the current process-id, either from the GlobalActivityTracker if it 64 // exists (where the PID can be defined for testing) or from the system if 65 // there isn't such. 66 int64_t GetProcessId() { 67 GlobalActivityTracker* global = GlobalActivityTracker::Get(); 68 if (global) 69 return global->process_id(); 70 return GetCurrentProcId(); 71 } 72 73 // Finds and reuses a specific allocation or creates a new one. 74 PersistentMemoryAllocator::Reference AllocateFrom( 75 PersistentMemoryAllocator* allocator, 76 uint32_t from_type, 77 size_t size, 78 uint32_t to_type) { 79 PersistentMemoryAllocator::Iterator iter(allocator); 80 PersistentMemoryAllocator::Reference ref; 81 while ((ref = iter.GetNextOfType(from_type)) != 0) { 82 DCHECK_LE(size, allocator->GetAllocSize(ref)); 83 // This can fail if a another thread has just taken it. It is assumed that 84 // the memory is cleared during the "free" operation. 85 if (allocator->ChangeType(ref, to_type, from_type, /*clear=*/false)) 86 return ref; 87 } 88 89 return allocator->Allocate(size, to_type); 90 } 91 92 // Determines the previous aligned index. 93 size_t RoundDownToAlignment(size_t index, size_t alignment) { 94 return index & (0 - alignment); 95 } 96 97 // Determines the next aligned index. 98 size_t RoundUpToAlignment(size_t index, size_t alignment) { 99 return (index + (alignment - 1)) & (0 - alignment); 100 } 101 102 // Converts "tick" timing into wall time. 103 Time WallTimeFromTickTime(int64_t ticks_start, int64_t ticks, Time time_start) { 104 return time_start + TimeDelta::FromInternalValue(ticks - ticks_start); 105 } 106 107 } // namespace 108 109 union ThreadRef { 110 int64_t as_id; 111 #if defined(OS_WIN) 112 // On Windows, the handle itself is often a pseudo-handle with a common 113 // value meaning "this thread" and so the thread-id is used. The former 114 // can be converted to a thread-id with a system call. 115 PlatformThreadId as_tid; 116 #elif defined(OS_POSIX) || defined(OS_FUCHSIA) 117 // On Posix and Fuchsia, the handle is always a unique identifier so no 118 // conversion needs to be done. However, its value is officially opaque so 119 // there is no one correct way to convert it to a numerical identifier. 120 PlatformThreadHandle::Handle as_handle; 121 #endif 122 }; 123 124 OwningProcess::OwningProcess() = default; 125 OwningProcess::~OwningProcess() = default; 126 127 void OwningProcess::Release_Initialize(int64_t pid) { 128 uint32_t old_id = data_id.load(std::memory_order_acquire); 129 DCHECK_EQ(0U, old_id); 130 process_id = pid != 0 ? pid : GetProcessId(); 131 create_stamp = Time::Now().ToInternalValue(); 132 data_id.store(GetNextDataId(), std::memory_order_release); 133 } 134 135 void OwningProcess::SetOwningProcessIdForTesting(int64_t pid, int64_t stamp) { 136 DCHECK_NE(0U, data_id); 137 process_id = pid; 138 create_stamp = stamp; 139 } 140 141 // static 142 bool OwningProcess::GetOwningProcessId(const void* memory, 143 int64_t* out_id, 144 int64_t* out_stamp) { 145 const OwningProcess* info = reinterpret_cast<const OwningProcess*>(memory); 146 uint32_t id = info->data_id.load(std::memory_order_acquire); 147 if (id == 0) 148 return false; 149 150 *out_id = info->process_id; 151 *out_stamp = info->create_stamp; 152 return id == info->data_id.load(std::memory_order_seq_cst); 153 } 154 155 // It doesn't matter what is contained in this (though it will be all zeros) 156 // as only the address of it is important. 157 const ActivityData kNullActivityData = {}; 158 159 ActivityData ActivityData::ForThread(const PlatformThreadHandle& handle) { 160 ThreadRef thread_ref; 161 thread_ref.as_id = 0; // Zero the union in case other is smaller. 162 #if defined(OS_WIN) 163 thread_ref.as_tid = ::GetThreadId(handle.platform_handle()); 164 #elif defined(OS_POSIX) 165 thread_ref.as_handle = handle.platform_handle(); 166 #endif 167 return ForThread(thread_ref.as_id); 168 } 169 170 ActivityTrackerMemoryAllocator::ActivityTrackerMemoryAllocator( 171 PersistentMemoryAllocator* allocator, 172 uint32_t object_type, 173 uint32_t object_free_type, 174 size_t object_size, 175 size_t cache_size, 176 bool make_iterable) 177 : allocator_(allocator), 178 object_type_(object_type), 179 object_free_type_(object_free_type), 180 object_size_(object_size), 181 cache_size_(cache_size), 182 make_iterable_(make_iterable), 183 iterator_(allocator), 184 cache_values_(new Reference[cache_size]), 185 cache_used_(0) { 186 DCHECK(allocator); 187 } 188 189 ActivityTrackerMemoryAllocator::~ActivityTrackerMemoryAllocator() = default; 190 191 ActivityTrackerMemoryAllocator::Reference 192 ActivityTrackerMemoryAllocator::GetObjectReference() { 193 // First see if there is a cached value that can be returned. This is much 194 // faster than searching the memory system for free blocks. 195 while (cache_used_ > 0) { 196 Reference cached = cache_values_[--cache_used_]; 197 // Change the type of the cached object to the proper type and return it. 198 // If the type-change fails that means another thread has taken this from 199 // under us (via the search below) so ignore it and keep trying. Don't 200 // clear the memory because that was done when the type was made "free". 201 if (allocator_->ChangeType(cached, object_type_, object_free_type_, false)) 202 return cached; 203 } 204 205 // Fetch the next "free" object from persistent memory. Rather than restart 206 // the iterator at the head each time and likely waste time going again 207 // through objects that aren't relevant, the iterator continues from where 208 // it last left off and is only reset when the end is reached. If the 209 // returned reference matches |last|, then it has wrapped without finding 210 // anything. 211 const Reference last = iterator_.GetLast(); 212 while (true) { 213 uint32_t type; 214 Reference found = iterator_.GetNext(&type); 215 if (found && type == object_free_type_) { 216 // Found a free object. Change it to the proper type and return it. If 217 // the type-change fails that means another thread has taken this from 218 // under us so ignore it and keep trying. 219 if (allocator_->ChangeType(found, object_type_, object_free_type_, false)) 220 return found; 221 } 222 if (found == last) { 223 // Wrapped. No desired object was found. 224 break; 225 } 226 if (!found) { 227 // Reached end; start over at the beginning. 228 iterator_.Reset(); 229 } 230 } 231 232 // No free block was found so instead allocate a new one. 233 Reference allocated = allocator_->Allocate(object_size_, object_type_); 234 if (allocated && make_iterable_) 235 allocator_->MakeIterable(allocated); 236 return allocated; 237 } 238 239 void ActivityTrackerMemoryAllocator::ReleaseObjectReference(Reference ref) { 240 // Mark object as free. 241 bool success = allocator_->ChangeType(ref, object_free_type_, object_type_, 242 /*clear=*/true); 243 DCHECK(success); 244 245 // Add this reference to our "free" cache if there is space. If not, the type 246 // has still been changed to indicate that it is free so this (or another) 247 // thread can find it, albeit more slowly, using the iteration method above. 248 if (cache_used_ < cache_size_) 249 cache_values_[cache_used_++] = ref; 250 } 251 252 // static 253 void Activity::FillFrom(Activity* activity, 254 const void* program_counter, 255 const void* origin, 256 Type type, 257 const ActivityData& data) { 258 activity->time_internal = base::TimeTicks::Now().ToInternalValue(); 259 activity->calling_address = reinterpret_cast<uintptr_t>(program_counter); 260 activity->origin_address = reinterpret_cast<uintptr_t>(origin); 261 activity->activity_type = type; 262 activity->data = data; 263 264 #if (!defined(OS_NACL) && DCHECK_IS_ON()) || defined(ADDRESS_SANITIZER) 265 // Create a stacktrace from the current location and get the addresses for 266 // improved debuggability. 267 StackTrace stack_trace; 268 size_t stack_depth; 269 const void* const* stack_addrs = stack_trace.Addresses(&stack_depth); 270 // Copy the stack addresses, ignoring the first one (here). 271 size_t i; 272 for (i = 1; i < stack_depth && i < kActivityCallStackSize; ++i) { 273 activity->call_stack[i - 1] = reinterpret_cast<uintptr_t>(stack_addrs[i]); 274 } 275 activity->call_stack[i - 1] = 0; 276 #else 277 activity->call_stack[0] = 0; 278 #endif 279 } 280 281 ActivityUserData::TypedValue::TypedValue() = default; 282 ActivityUserData::TypedValue::TypedValue(const TypedValue& other) = default; 283 ActivityUserData::TypedValue::~TypedValue() = default; 284 285 StringPiece ActivityUserData::TypedValue::Get() const { 286 DCHECK_EQ(RAW_VALUE, type_); 287 return long_value_; 288 } 289 290 StringPiece ActivityUserData::TypedValue::GetString() const { 291 DCHECK_EQ(STRING_VALUE, type_); 292 return long_value_; 293 } 294 295 bool ActivityUserData::TypedValue::GetBool() const { 296 DCHECK_EQ(BOOL_VALUE, type_); 297 return short_value_ != 0; 298 } 299 300 char ActivityUserData::TypedValue::GetChar() const { 301 DCHECK_EQ(CHAR_VALUE, type_); 302 return static_cast<char>(short_value_); 303 } 304 305 int64_t ActivityUserData::TypedValue::GetInt() const { 306 DCHECK_EQ(SIGNED_VALUE, type_); 307 return static_cast<int64_t>(short_value_); 308 } 309 310 uint64_t ActivityUserData::TypedValue::GetUint() const { 311 DCHECK_EQ(UNSIGNED_VALUE, type_); 312 return static_cast<uint64_t>(short_value_); 313 } 314 315 StringPiece ActivityUserData::TypedValue::GetReference() const { 316 DCHECK_EQ(RAW_VALUE_REFERENCE, type_); 317 return ref_value_; 318 } 319 320 StringPiece ActivityUserData::TypedValue::GetStringReference() const { 321 DCHECK_EQ(STRING_VALUE_REFERENCE, type_); 322 return ref_value_; 323 } 324 325 // These are required because std::atomic is (currently) not a POD type and 326 // thus clang requires explicit out-of-line constructors and destructors even 327 // when they do nothing. 328 ActivityUserData::ValueInfo::ValueInfo() = default; 329 ActivityUserData::ValueInfo::ValueInfo(ValueInfo&&) = default; 330 ActivityUserData::ValueInfo::~ValueInfo() = default; 331 ActivityUserData::MemoryHeader::MemoryHeader() = default; 332 ActivityUserData::MemoryHeader::~MemoryHeader() = default; 333 ActivityUserData::FieldHeader::FieldHeader() = default; 334 ActivityUserData::FieldHeader::~FieldHeader() = default; 335 336 ActivityUserData::ActivityUserData() : ActivityUserData(nullptr, 0, -1) {} 337 338 ActivityUserData::ActivityUserData(void* memory, size_t size, int64_t pid) 339 : memory_(reinterpret_cast<char*>(memory)), 340 available_(RoundDownToAlignment(size, kMemoryAlignment)), 341 header_(reinterpret_cast<MemoryHeader*>(memory)), 342 orig_data_id(0), 343 orig_process_id(0), 344 orig_create_stamp(0) { 345 // It's possible that no user data is being stored. 346 if (!memory_) 347 return; 348 349 static_assert(0 == sizeof(MemoryHeader) % kMemoryAlignment, "invalid header"); 350 DCHECK_LT(sizeof(MemoryHeader), available_); 351 if (header_->owner.data_id.load(std::memory_order_acquire) == 0) 352 header_->owner.Release_Initialize(pid); 353 memory_ += sizeof(MemoryHeader); 354 available_ -= sizeof(MemoryHeader); 355 356 // Make a copy of identifying information for later comparison. 357 *const_cast<uint32_t*>(&orig_data_id) = 358 header_->owner.data_id.load(std::memory_order_acquire); 359 *const_cast<int64_t*>(&orig_process_id) = header_->owner.process_id; 360 *const_cast<int64_t*>(&orig_create_stamp) = header_->owner.create_stamp; 361 362 // If there is already data present, load that. This allows the same class 363 // to be used for analysis through snapshots. 364 ImportExistingData(); 365 } 366 367 ActivityUserData::~ActivityUserData() = default; 368 369 bool ActivityUserData::CreateSnapshot(Snapshot* output_snapshot) const { 370 DCHECK(output_snapshot); 371 DCHECK(output_snapshot->empty()); 372 373 // Find any new data that may have been added by an active instance of this 374 // class that is adding records. 375 ImportExistingData(); 376 377 // Add all the values to the snapshot. 378 for (const auto& entry : values_) { 379 TypedValue value; 380 const size_t size = entry.second.size_ptr->load(std::memory_order_acquire); 381 value.type_ = entry.second.type; 382 DCHECK_GE(entry.second.extent, size); 383 384 switch (entry.second.type) { 385 case RAW_VALUE: 386 case STRING_VALUE: 387 value.long_value_ = 388 std::string(reinterpret_cast<char*>(entry.second.memory), size); 389 break; 390 case RAW_VALUE_REFERENCE: 391 case STRING_VALUE_REFERENCE: { 392 ReferenceRecord* ref = 393 reinterpret_cast<ReferenceRecord*>(entry.second.memory); 394 value.ref_value_ = StringPiece( 395 reinterpret_cast<char*>(static_cast<uintptr_t>(ref->address)), 396 static_cast<size_t>(ref->size)); 397 } break; 398 case BOOL_VALUE: 399 case CHAR_VALUE: 400 value.short_value_ = *reinterpret_cast<char*>(entry.second.memory); 401 break; 402 case SIGNED_VALUE: 403 case UNSIGNED_VALUE: 404 value.short_value_ = *reinterpret_cast<uint64_t*>(entry.second.memory); 405 break; 406 case END_OF_VALUES: // Included for completeness purposes. 407 NOTREACHED(); 408 } 409 auto inserted = output_snapshot->insert( 410 std::make_pair(entry.second.name.as_string(), std::move(value))); 411 DCHECK(inserted.second); // True if inserted, false if existed. 412 } 413 414 // Another import attempt will validate that the underlying memory has not 415 // been reused for another purpose. Entries added since the first import 416 // will be ignored here but will be returned if another snapshot is created. 417 ImportExistingData(); 418 if (!memory_) { 419 output_snapshot->clear(); 420 return false; 421 } 422 423 // Successful snapshot. 424 return true; 425 } 426 427 const void* ActivityUserData::GetBaseAddress() const { 428 // The |memory_| pointer advances as elements are written but the |header_| 429 // value is always at the start of the block so just return that. 430 return header_; 431 } 432 433 void ActivityUserData::SetOwningProcessIdForTesting(int64_t pid, 434 int64_t stamp) { 435 if (!header_) 436 return; 437 header_->owner.SetOwningProcessIdForTesting(pid, stamp); 438 } 439 440 // static 441 bool ActivityUserData::GetOwningProcessId(const void* memory, 442 int64_t* out_id, 443 int64_t* out_stamp) { 444 const MemoryHeader* header = reinterpret_cast<const MemoryHeader*>(memory); 445 return OwningProcess::GetOwningProcessId(&header->owner, out_id, out_stamp); 446 } 447 448 void ActivityUserData::Set(StringPiece name, 449 ValueType type, 450 const void* memory, 451 size_t size) { 452 DCHECK_GE(std::numeric_limits<uint8_t>::max(), name.length()); 453 size = std::min(std::numeric_limits<uint16_t>::max() - (kMemoryAlignment - 1), 454 size); 455 456 // It's possible that no user data is being stored. 457 if (!memory_) 458 return; 459 460 // The storage of a name is limited so use that limit during lookup. 461 if (name.length() > kMaxUserDataNameLength) 462 name.set(name.data(), kMaxUserDataNameLength); 463 464 ValueInfo* info; 465 auto existing = values_.find(name); 466 if (existing != values_.end()) { 467 info = &existing->second; 468 } else { 469 // The name size is limited to what can be held in a single byte but 470 // because there are not alignment constraints on strings, it's set tight 471 // against the header. Its extent (the reserved space, even if it's not 472 // all used) is calculated so that, when pressed against the header, the 473 // following field will be aligned properly. 474 size_t name_size = name.length(); 475 size_t name_extent = 476 RoundUpToAlignment(sizeof(FieldHeader) + name_size, kMemoryAlignment) - 477 sizeof(FieldHeader); 478 size_t value_extent = RoundUpToAlignment(size, kMemoryAlignment); 479 480 // The "base size" is the size of the header and (padded) string key. Stop 481 // now if there's not room enough for even this. 482 size_t base_size = sizeof(FieldHeader) + name_extent; 483 if (base_size > available_) 484 return; 485 486 // The "full size" is the size for storing the entire value. 487 size_t full_size = std::min(base_size + value_extent, available_); 488 489 // If the value is actually a single byte, see if it can be stuffed at the 490 // end of the name extent rather than wasting kMemoryAlignment bytes. 491 if (size == 1 && name_extent > name_size) { 492 full_size = base_size; 493 --name_extent; 494 --base_size; 495 } 496 497 // Truncate the stored size to the amount of available memory. Stop now if 498 // there's not any room for even part of the value. 499 if (size != 0) { 500 size = std::min(full_size - base_size, size); 501 if (size == 0) 502 return; 503 } 504 505 // Allocate a chunk of memory. 506 FieldHeader* header = reinterpret_cast<FieldHeader*>(memory_); 507 memory_ += full_size; 508 available_ -= full_size; 509 510 // Datafill the header and name records. Memory must be zeroed. The |type| 511 // is written last, atomically, to release all the other values. 512 DCHECK_EQ(END_OF_VALUES, header->type.load(std::memory_order_relaxed)); 513 DCHECK_EQ(0, header->value_size.load(std::memory_order_relaxed)); 514 header->name_size = static_cast<uint8_t>(name_size); 515 header->record_size = full_size; 516 char* name_memory = reinterpret_cast<char*>(header) + sizeof(FieldHeader); 517 void* value_memory = 518 reinterpret_cast<char*>(header) + sizeof(FieldHeader) + name_extent; 519 memcpy(name_memory, name.data(), name_size); 520 header->type.store(type, std::memory_order_release); 521 522 // Create an entry in |values_| so that this field can be found and changed 523 // later on without having to allocate new entries. 524 StringPiece persistent_name(name_memory, name_size); 525 auto inserted = 526 values_.insert(std::make_pair(persistent_name, ValueInfo())); 527 DCHECK(inserted.second); // True if inserted, false if existed. 528 info = &inserted.first->second; 529 info->name = persistent_name; 530 info->memory = value_memory; 531 info->size_ptr = &header->value_size; 532 info->extent = full_size - sizeof(FieldHeader) - name_extent; 533 info->type = type; 534 } 535 536 // Copy the value data to storage. The |size| is written last, atomically, to 537 // release the copied data. Until then, a parallel reader will just ignore 538 // records with a zero size. 539 DCHECK_EQ(type, info->type); 540 size = std::min(size, info->extent); 541 info->size_ptr->store(0, std::memory_order_seq_cst); 542 memcpy(info->memory, memory, size); 543 info->size_ptr->store(size, std::memory_order_release); 544 } 545 546 void ActivityUserData::SetReference(StringPiece name, 547 ValueType type, 548 const void* memory, 549 size_t size) { 550 ReferenceRecord rec; 551 rec.address = reinterpret_cast<uintptr_t>(memory); 552 rec.size = size; 553 Set(name, type, &rec, sizeof(rec)); 554 } 555 556 void ActivityUserData::ImportExistingData() const { 557 // It's possible that no user data is being stored. 558 if (!memory_) 559 return; 560 561 while (available_ > sizeof(FieldHeader)) { 562 FieldHeader* header = reinterpret_cast<FieldHeader*>(memory_); 563 ValueType type = 564 static_cast<ValueType>(header->type.load(std::memory_order_acquire)); 565 if (type == END_OF_VALUES) 566 return; 567 if (header->record_size > available_) 568 return; 569 570 size_t value_offset = RoundUpToAlignment( 571 sizeof(FieldHeader) + header->name_size, kMemoryAlignment); 572 if (header->record_size == value_offset && 573 header->value_size.load(std::memory_order_relaxed) == 1) { 574 value_offset -= 1; 575 } 576 if (value_offset + header->value_size > header->record_size) 577 return; 578 579 ValueInfo info; 580 info.name = StringPiece(memory_ + sizeof(FieldHeader), header->name_size); 581 info.type = type; 582 info.memory = memory_ + value_offset; 583 info.size_ptr = &header->value_size; 584 info.extent = header->record_size - value_offset; 585 586 StringPiece key(info.name); 587 values_.insert(std::make_pair(key, std::move(info))); 588 589 memory_ += header->record_size; 590 available_ -= header->record_size; 591 } 592 593 // Check if memory has been completely reused. 594 if (header_->owner.data_id.load(std::memory_order_acquire) != orig_data_id || 595 header_->owner.process_id != orig_process_id || 596 header_->owner.create_stamp != orig_create_stamp) { 597 memory_ = nullptr; 598 values_.clear(); 599 } 600 } 601 602 // This information is kept for every thread that is tracked. It is filled 603 // the very first time the thread is seen. All fields must be of exact sizes 604 // so there is no issue moving between 32 and 64-bit builds. 605 struct ThreadActivityTracker::Header { 606 // Defined in .h for analyzer access. Increment this if structure changes! 607 static constexpr uint32_t kPersistentTypeId = 608 GlobalActivityTracker::kTypeIdActivityTracker; 609 610 // Expected size for 32/64-bit check. 611 static constexpr size_t kExpectedInstanceSize = 612 OwningProcess::kExpectedInstanceSize + Activity::kExpectedInstanceSize + 613 72; 614 615 // This information uniquely identifies a process. 616 OwningProcess owner; 617 618 // The thread-id (thread_ref.as_id) to which this data belongs. This number 619 // is not guaranteed to mean anything but combined with the process-id from 620 // OwningProcess is unique among all active trackers. 621 ThreadRef thread_ref; 622 623 // The start-time and start-ticks when the data was created. Each activity 624 // record has a |time_internal| value that can be converted to a "wall time" 625 // with these two values. 626 int64_t start_time; 627 int64_t start_ticks; 628 629 // The number of Activity slots (spaces that can hold an Activity) that 630 // immediately follow this structure in memory. 631 uint32_t stack_slots; 632 633 // Some padding to keep everything 64-bit aligned. 634 uint32_t padding; 635 636 // The current depth of the stack. This may be greater than the number of 637 // slots. If the depth exceeds the number of slots, the newest entries 638 // won't be recorded. 639 std::atomic<uint32_t> current_depth; 640 641 // A memory location used to indicate if changes have been made to the data 642 // that would invalidate an in-progress read of its contents. The active 643 // tracker will increment the value whenever something gets popped from the 644 // stack. A monitoring tracker can check the value before and after access 645 // to know, if it's still the same, that the contents didn't change while 646 // being copied. 647 std::atomic<uint32_t> data_version; 648 649 // The last "exception" activity. This can't be stored on the stack because 650 // that could get popped as things unwind. 651 Activity last_exception; 652 653 // The name of the thread (up to a maximum length). Dynamic-length names 654 // are not practical since the memory has to come from the same persistent 655 // allocator that holds this structure and to which this object has no 656 // reference. 657 char thread_name[32]; 658 }; 659 660 ThreadActivityTracker::Snapshot::Snapshot() = default; 661 ThreadActivityTracker::Snapshot::~Snapshot() = default; 662 663 ThreadActivityTracker::ScopedActivity::ScopedActivity( 664 ThreadActivityTracker* tracker, 665 const void* program_counter, 666 const void* origin, 667 Activity::Type type, 668 const ActivityData& data) 669 : tracker_(tracker) { 670 if (tracker_) 671 activity_id_ = tracker_->PushActivity(program_counter, origin, type, data); 672 } 673 674 ThreadActivityTracker::ScopedActivity::~ScopedActivity() { 675 if (tracker_) 676 tracker_->PopActivity(activity_id_); 677 } 678 679 void ThreadActivityTracker::ScopedActivity::ChangeTypeAndData( 680 Activity::Type type, 681 const ActivityData& data) { 682 if (tracker_) 683 tracker_->ChangeActivity(activity_id_, type, data); 684 } 685 686 ThreadActivityTracker::ThreadActivityTracker(void* base, size_t size) 687 : header_(static_cast<Header*>(base)), 688 stack_(reinterpret_cast<Activity*>(reinterpret_cast<char*>(base) + 689 sizeof(Header))), 690 #if DCHECK_IS_ON() 691 thread_id_(PlatformThreadRef()), 692 #endif 693 stack_slots_( 694 static_cast<uint32_t>((size - sizeof(Header)) / sizeof(Activity))) { 695 696 // Verify the parameters but fail gracefully if they're not valid so that 697 // production code based on external inputs will not crash. IsValid() will 698 // return false in this case. 699 if (!base || 700 // Ensure there is enough space for the header and at least a few records. 701 size < sizeof(Header) + kMinStackDepth * sizeof(Activity) || 702 // Ensure that the |stack_slots_| calculation didn't overflow. 703 (size - sizeof(Header)) / sizeof(Activity) > 704 std::numeric_limits<uint32_t>::max()) { 705 NOTREACHED(); 706 return; 707 } 708 709 // Ensure that the thread reference doesn't exceed the size of the ID number. 710 // This won't compile at the global scope because Header is a private struct. 711 static_assert( 712 sizeof(header_->thread_ref) == sizeof(header_->thread_ref.as_id), 713 "PlatformThreadHandle::Handle is too big to hold in 64-bit ID"); 714 715 // Ensure that the alignment of Activity.data is properly aligned to a 716 // 64-bit boundary so there are no interoperability-issues across cpu 717 // architectures. 718 static_assert(offsetof(Activity, data) % sizeof(uint64_t) == 0, 719 "ActivityData.data is not 64-bit aligned"); 720 721 // Provided memory should either be completely initialized or all zeros. 722 if (header_->owner.data_id.load(std::memory_order_relaxed) == 0) { 723 // This is a new file. Double-check other fields and then initialize. 724 DCHECK_EQ(0, header_->owner.process_id); 725 DCHECK_EQ(0, header_->owner.create_stamp); 726 DCHECK_EQ(0, header_->thread_ref.as_id); 727 DCHECK_EQ(0, header_->start_time); 728 DCHECK_EQ(0, header_->start_ticks); 729 DCHECK_EQ(0U, header_->stack_slots); 730 DCHECK_EQ(0U, header_->current_depth.load(std::memory_order_relaxed)); 731 DCHECK_EQ(0U, header_->data_version.load(std::memory_order_relaxed)); 732 DCHECK_EQ(0, stack_[0].time_internal); 733 DCHECK_EQ(0U, stack_[0].origin_address); 734 DCHECK_EQ(0U, stack_[0].call_stack[0]); 735 DCHECK_EQ(0U, stack_[0].data.task.sequence_id); 736 737 #if defined(OS_WIN) 738 header_->thread_ref.as_tid = PlatformThread::CurrentId(); 739 #elif defined(OS_POSIX) || defined(OS_FUCHSIA) 740 header_->thread_ref.as_handle = 741 PlatformThread::CurrentHandle().platform_handle(); 742 #endif 743 744 header_->start_time = base::Time::Now().ToInternalValue(); 745 header_->start_ticks = base::TimeTicks::Now().ToInternalValue(); 746 header_->stack_slots = stack_slots_; 747 strlcpy(header_->thread_name, PlatformThread::GetName(), 748 sizeof(header_->thread_name)); 749 750 // This is done last so as to guarantee that everything above is "released" 751 // by the time this value gets written. 752 header_->owner.Release_Initialize(); 753 754 valid_ = true; 755 DCHECK(IsValid()); 756 } else { 757 // This is a file with existing data. Perform basic consistency checks. 758 valid_ = true; 759 valid_ = IsValid(); 760 } 761 } 762 763 ThreadActivityTracker::~ThreadActivityTracker() = default; 764 765 ThreadActivityTracker::ActivityId ThreadActivityTracker::PushActivity( 766 const void* program_counter, 767 const void* origin, 768 Activity::Type type, 769 const ActivityData& data) { 770 // A thread-checker creates a lock to check the thread-id which means 771 // re-entry into this code if lock acquisitions are being tracked. 772 DCHECK(type == Activity::ACT_LOCK_ACQUIRE || CalledOnValidThread()); 773 774 // Get the current depth of the stack. No access to other memory guarded 775 // by this variable is done here so a "relaxed" load is acceptable. 776 uint32_t depth = header_->current_depth.load(std::memory_order_relaxed); 777 778 // Handle the case where the stack depth has exceeded the storage capacity. 779 // Extra entries will be lost leaving only the base of the stack. 780 if (depth >= stack_slots_) { 781 // Since no other threads modify the data, no compare/exchange is needed. 782 // Since no other memory is being modified, a "relaxed" store is acceptable. 783 header_->current_depth.store(depth + 1, std::memory_order_relaxed); 784 return depth; 785 } 786 787 // Get a pointer to the next activity and load it. No atomicity is required 788 // here because the memory is known only to this thread. It will be made 789 // known to other threads once the depth is incremented. 790 Activity::FillFrom(&stack_[depth], program_counter, origin, type, data); 791 792 // Save the incremented depth. Because this guards |activity| memory filled 793 // above that may be read by another thread once the recorded depth changes, 794 // a "release" store is required. 795 header_->current_depth.store(depth + 1, std::memory_order_release); 796 797 // The current depth is used as the activity ID because it simply identifies 798 // an entry. Once an entry is pop'd, it's okay to reuse the ID. 799 return depth; 800 } 801 802 void ThreadActivityTracker::ChangeActivity(ActivityId id, 803 Activity::Type type, 804 const ActivityData& data) { 805 DCHECK(CalledOnValidThread()); 806 DCHECK(type != Activity::ACT_NULL || &data != &kNullActivityData); 807 DCHECK_LT(id, header_->current_depth.load(std::memory_order_acquire)); 808 809 // Update the information if it is being recorded (i.e. within slot limit). 810 if (id < stack_slots_) { 811 Activity* activity = &stack_[id]; 812 813 if (type != Activity::ACT_NULL) { 814 DCHECK_EQ(activity->activity_type & Activity::ACT_CATEGORY_MASK, 815 type & Activity::ACT_CATEGORY_MASK); 816 activity->activity_type = type; 817 } 818 819 if (&data != &kNullActivityData) 820 activity->data = data; 821 } 822 } 823 824 void ThreadActivityTracker::PopActivity(ActivityId id) { 825 // Do an atomic decrement of the depth. No changes to stack entries guarded 826 // by this variable are done here so a "relaxed" operation is acceptable. 827 // |depth| will receive the value BEFORE it was modified which means the 828 // return value must also be decremented. The slot will be "free" after 829 // this call but since only a single thread can access this object, the 830 // data will remain valid until this method returns or calls outside. 831 uint32_t depth = 832 header_->current_depth.fetch_sub(1, std::memory_order_relaxed) - 1; 833 834 // Validate that everything is running correctly. 835 DCHECK_EQ(id, depth); 836 837 // A thread-checker creates a lock to check the thread-id which means 838 // re-entry into this code if lock acquisitions are being tracked. 839 DCHECK(stack_[depth].activity_type == Activity::ACT_LOCK_ACQUIRE || 840 CalledOnValidThread()); 841 842 // The stack has shrunk meaning that some other thread trying to copy the 843 // contents for reporting purposes could get bad data. Increment the data 844 // version so that it con tell that things have changed. This needs to 845 // happen after the atomic |depth| operation above so a "release" store 846 // is required. 847 header_->data_version.fetch_add(1, std::memory_order_release); 848 } 849 850 std::unique_ptr<ActivityUserData> ThreadActivityTracker::GetUserData( 851 ActivityId id, 852 ActivityTrackerMemoryAllocator* allocator) { 853 // Don't allow user data for lock acquisition as recursion may occur. 854 if (stack_[id].activity_type == Activity::ACT_LOCK_ACQUIRE) { 855 NOTREACHED(); 856 return std::make_unique<ActivityUserData>(); 857 } 858 859 // User-data is only stored for activities actually held in the stack. 860 if (id >= stack_slots_) 861 return std::make_unique<ActivityUserData>(); 862 863 // Create and return a real UserData object. 864 return CreateUserDataForActivity(&stack_[id], allocator); 865 } 866 867 bool ThreadActivityTracker::HasUserData(ActivityId id) { 868 // User-data is only stored for activities actually held in the stack. 869 return (id < stack_slots_ && stack_[id].user_data_ref); 870 } 871 872 void ThreadActivityTracker::ReleaseUserData( 873 ActivityId id, 874 ActivityTrackerMemoryAllocator* allocator) { 875 // User-data is only stored for activities actually held in the stack. 876 if (id < stack_slots_ && stack_[id].user_data_ref) { 877 allocator->ReleaseObjectReference(stack_[id].user_data_ref); 878 stack_[id].user_data_ref = 0; 879 } 880 } 881 882 void ThreadActivityTracker::RecordExceptionActivity(const void* program_counter, 883 const void* origin, 884 Activity::Type type, 885 const ActivityData& data) { 886 // A thread-checker creates a lock to check the thread-id which means 887 // re-entry into this code if lock acquisitions are being tracked. 888 DCHECK(CalledOnValidThread()); 889 890 // Fill the reusable exception activity. 891 Activity::FillFrom(&header_->last_exception, program_counter, origin, type, 892 data); 893 894 // The data has changed meaning that some other thread trying to copy the 895 // contents for reporting purposes could get bad data. 896 header_->data_version.fetch_add(1, std::memory_order_relaxed); 897 } 898 899 bool ThreadActivityTracker::IsValid() const { 900 if (header_->owner.data_id.load(std::memory_order_acquire) == 0 || 901 header_->owner.process_id == 0 || header_->thread_ref.as_id == 0 || 902 header_->start_time == 0 || header_->start_ticks == 0 || 903 header_->stack_slots != stack_slots_ || 904 header_->thread_name[sizeof(header_->thread_name) - 1] != '\0') { 905 return false; 906 } 907 908 return valid_; 909 } 910 911 bool ThreadActivityTracker::CreateSnapshot(Snapshot* output_snapshot) const { 912 DCHECK(output_snapshot); 913 914 // There is no "called on valid thread" check for this method as it can be 915 // called from other threads or even other processes. It is also the reason 916 // why atomic operations must be used in certain places above. 917 918 // It's possible for the data to change while reading it in such a way that it 919 // invalidates the read. Make several attempts but don't try forever. 920 const int kMaxAttempts = 10; 921 uint32_t depth; 922 923 // Stop here if the data isn't valid. 924 if (!IsValid()) 925 return false; 926 927 // Allocate the maximum size for the stack so it doesn't have to be done 928 // during the time-sensitive snapshot operation. It is shrunk once the 929 // actual size is known. 930 output_snapshot->activity_stack.reserve(stack_slots_); 931 932 for (int attempt = 0; attempt < kMaxAttempts; ++attempt) { 933 // Remember the data IDs to ensure nothing is replaced during the snapshot 934 // operation. Use "acquire" so that all the non-atomic fields of the 935 // structure are valid (at least at the current moment in time). 936 const uint32_t starting_id = 937 header_->owner.data_id.load(std::memory_order_acquire); 938 const int64_t starting_create_stamp = header_->owner.create_stamp; 939 const int64_t starting_process_id = header_->owner.process_id; 940 const int64_t starting_thread_id = header_->thread_ref.as_id; 941 942 // Note the current |data_version| so it's possible to detect at the end 943 // that nothing has changed since copying the data began. A "cst" operation 944 // is required to ensure it occurs before everything else. Using "cst" 945 // memory ordering is relatively expensive but this is only done during 946 // analysis so doesn't directly affect the worker threads. 947 const uint32_t pre_version = 948 header_->data_version.load(std::memory_order_seq_cst); 949 950 // Fetching the current depth also "acquires" the contents of the stack. 951 depth = header_->current_depth.load(std::memory_order_acquire); 952 uint32_t count = std::min(depth, stack_slots_); 953 output_snapshot->activity_stack.resize(count); 954 if (count > 0) { 955 // Copy the existing contents. Memcpy is used for speed. 956 memcpy(&output_snapshot->activity_stack[0], stack_, 957 count * sizeof(Activity)); 958 } 959 960 // Capture the last exception. 961 memcpy(&output_snapshot->last_exception, &header_->last_exception, 962 sizeof(Activity)); 963 964 // TODO(bcwhite): Snapshot other things here. 965 966 // Retry if something changed during the copy. A "cst" operation ensures 967 // it must happen after all the above operations. 968 if (header_->data_version.load(std::memory_order_seq_cst) != pre_version) 969 continue; 970 971 // Stack copied. Record it's full depth. 972 output_snapshot->activity_stack_depth = depth; 973 974 // Get the general thread information. 975 output_snapshot->thread_name = 976 std::string(header_->thread_name, sizeof(header_->thread_name) - 1); 977 output_snapshot->create_stamp = header_->owner.create_stamp; 978 output_snapshot->thread_id = header_->thread_ref.as_id; 979 output_snapshot->process_id = header_->owner.process_id; 980 981 // All characters of the thread-name buffer were copied so as to not break 982 // if the trailing NUL were missing. Now limit the length if the actual 983 // name is shorter. 984 output_snapshot->thread_name.resize( 985 strlen(output_snapshot->thread_name.c_str())); 986 987 // If the data ID has changed then the tracker has exited and the memory 988 // reused by a new one. Try again. 989 if (header_->owner.data_id.load(std::memory_order_seq_cst) != starting_id || 990 output_snapshot->create_stamp != starting_create_stamp || 991 output_snapshot->process_id != starting_process_id || 992 output_snapshot->thread_id != starting_thread_id) { 993 continue; 994 } 995 996 // Only successful if the data is still valid once everything is done since 997 // it's possible for the thread to end somewhere in the middle and all its 998 // values become garbage. 999 if (!IsValid()) 1000 return false; 1001 1002 // Change all the timestamps in the activities from "ticks" to "wall" time. 1003 const Time start_time = Time::FromInternalValue(header_->start_time); 1004 const int64_t start_ticks = header_->start_ticks; 1005 for (Activity& activity : output_snapshot->activity_stack) { 1006 activity.time_internal = 1007 WallTimeFromTickTime(start_ticks, activity.time_internal, start_time) 1008 .ToInternalValue(); 1009 } 1010 output_snapshot->last_exception.time_internal = 1011 WallTimeFromTickTime(start_ticks, 1012 output_snapshot->last_exception.time_internal, 1013 start_time) 1014 .ToInternalValue(); 1015 1016 // Success! 1017 return true; 1018 } 1019 1020 // Too many attempts. 1021 return false; 1022 } 1023 1024 const void* ThreadActivityTracker::GetBaseAddress() { 1025 return header_; 1026 } 1027 1028 uint32_t ThreadActivityTracker::GetDataVersionForTesting() { 1029 return header_->data_version.load(std::memory_order_relaxed); 1030 } 1031 1032 void ThreadActivityTracker::SetOwningProcessIdForTesting(int64_t pid, 1033 int64_t stamp) { 1034 header_->owner.SetOwningProcessIdForTesting(pid, stamp); 1035 } 1036 1037 // static 1038 bool ThreadActivityTracker::GetOwningProcessId(const void* memory, 1039 int64_t* out_id, 1040 int64_t* out_stamp) { 1041 const Header* header = reinterpret_cast<const Header*>(memory); 1042 return OwningProcess::GetOwningProcessId(&header->owner, out_id, out_stamp); 1043 } 1044 1045 // static 1046 size_t ThreadActivityTracker::SizeForStackDepth(int stack_depth) { 1047 return static_cast<size_t>(stack_depth) * sizeof(Activity) + sizeof(Header); 1048 } 1049 1050 bool ThreadActivityTracker::CalledOnValidThread() { 1051 #if DCHECK_IS_ON() 1052 return thread_id_ == PlatformThreadRef(); 1053 #else 1054 return true; 1055 #endif 1056 } 1057 1058 std::unique_ptr<ActivityUserData> 1059 ThreadActivityTracker::CreateUserDataForActivity( 1060 Activity* activity, 1061 ActivityTrackerMemoryAllocator* allocator) { 1062 DCHECK_EQ(0U, activity->user_data_ref); 1063 1064 PersistentMemoryAllocator::Reference ref = allocator->GetObjectReference(); 1065 void* memory = allocator->GetAsArray<char>(ref, kUserDataSize); 1066 if (memory) { 1067 std::unique_ptr<ActivityUserData> user_data = 1068 std::make_unique<ActivityUserData>(memory, kUserDataSize); 1069 activity->user_data_ref = ref; 1070 activity->user_data_id = user_data->id(); 1071 return user_data; 1072 } 1073 1074 // Return a dummy object that will still accept (but ignore) Set() calls. 1075 return std::make_unique<ActivityUserData>(); 1076 } 1077 1078 // The instantiation of the GlobalActivityTracker object. 1079 // The object held here will obviously not be destructed at process exit 1080 // but that's best since PersistentMemoryAllocator objects (that underlie 1081 // GlobalActivityTracker objects) are explicitly forbidden from doing anything 1082 // essential at exit anyway due to the fact that they depend on data managed 1083 // elsewhere and which could be destructed first. An AtomicWord is used instead 1084 // of std::atomic because the latter can create global ctors and dtors. 1085 subtle::AtomicWord GlobalActivityTracker::g_tracker_ = 0; 1086 1087 GlobalActivityTracker::ModuleInfo::ModuleInfo() = default; 1088 GlobalActivityTracker::ModuleInfo::ModuleInfo(ModuleInfo&& rhs) = default; 1089 GlobalActivityTracker::ModuleInfo::ModuleInfo(const ModuleInfo& rhs) = default; 1090 GlobalActivityTracker::ModuleInfo::~ModuleInfo() = default; 1091 1092 GlobalActivityTracker::ModuleInfo& GlobalActivityTracker::ModuleInfo::operator=( 1093 ModuleInfo&& rhs) = default; 1094 GlobalActivityTracker::ModuleInfo& GlobalActivityTracker::ModuleInfo::operator=( 1095 const ModuleInfo& rhs) = default; 1096 1097 GlobalActivityTracker::ModuleInfoRecord::ModuleInfoRecord() = default; 1098 GlobalActivityTracker::ModuleInfoRecord::~ModuleInfoRecord() = default; 1099 1100 bool GlobalActivityTracker::ModuleInfoRecord::DecodeTo( 1101 GlobalActivityTracker::ModuleInfo* info, 1102 size_t record_size) const { 1103 // Get the current "changes" indicator, acquiring all the other values. 1104 uint32_t current_changes = changes.load(std::memory_order_acquire); 1105 1106 // Copy out the dynamic information. 1107 info->is_loaded = loaded != 0; 1108 info->address = static_cast<uintptr_t>(address); 1109 info->load_time = load_time; 1110 1111 // Check to make sure no information changed while being read. A "seq-cst" 1112 // operation is expensive but is only done during analysis and it's the only 1113 // way to ensure this occurs after all the accesses above. If changes did 1114 // occur then return a "not loaded" result so that |size| and |address| 1115 // aren't expected to be accurate. 1116 if ((current_changes & kModuleInformationChanging) != 0 || 1117 changes.load(std::memory_order_seq_cst) != current_changes) { 1118 info->is_loaded = false; 1119 } 1120 1121 // Copy out the static information. These never change so don't have to be 1122 // protected by the atomic |current_changes| operations. 1123 info->size = static_cast<size_t>(size); 1124 info->timestamp = timestamp; 1125 info->age = age; 1126 memcpy(info->identifier, identifier, sizeof(info->identifier)); 1127 1128 if (offsetof(ModuleInfoRecord, pickle) + pickle_size > record_size) 1129 return false; 1130 Pickle pickler(pickle, pickle_size); 1131 PickleIterator iter(pickler); 1132 return iter.ReadString(&info->file) && iter.ReadString(&info->debug_file); 1133 } 1134 1135 GlobalActivityTracker::ModuleInfoRecord* 1136 GlobalActivityTracker::ModuleInfoRecord::CreateFrom( 1137 const GlobalActivityTracker::ModuleInfo& info, 1138 PersistentMemoryAllocator* allocator) { 1139 Pickle pickler; 1140 pickler.WriteString(info.file); 1141 pickler.WriteString(info.debug_file); 1142 size_t required_size = offsetof(ModuleInfoRecord, pickle) + pickler.size(); 1143 ModuleInfoRecord* record = allocator->New<ModuleInfoRecord>(required_size); 1144 if (!record) 1145 return nullptr; 1146 1147 // These fields never changes and are done before the record is made 1148 // iterable so no thread protection is necessary. 1149 record->size = info.size; 1150 record->timestamp = info.timestamp; 1151 record->age = info.age; 1152 memcpy(record->identifier, info.identifier, sizeof(identifier)); 1153 memcpy(record->pickle, pickler.data(), pickler.size()); 1154 record->pickle_size = pickler.size(); 1155 record->changes.store(0, std::memory_order_relaxed); 1156 1157 // Initialize the owner info. 1158 record->owner.Release_Initialize(); 1159 1160 // Now set those fields that can change. 1161 bool success = record->UpdateFrom(info); 1162 DCHECK(success); 1163 return record; 1164 } 1165 1166 bool GlobalActivityTracker::ModuleInfoRecord::UpdateFrom( 1167 const GlobalActivityTracker::ModuleInfo& info) { 1168 // Updates can occur after the record is made visible so make changes atomic. 1169 // A "strong" exchange ensures no false failures. 1170 uint32_t old_changes = changes.load(std::memory_order_relaxed); 1171 uint32_t new_changes = old_changes | kModuleInformationChanging; 1172 if ((old_changes & kModuleInformationChanging) != 0 || 1173 !changes.compare_exchange_strong(old_changes, new_changes, 1174 std::memory_order_acquire, 1175 std::memory_order_acquire)) { 1176 NOTREACHED() << "Multiple sources are updating module information."; 1177 return false; 1178 } 1179 1180 loaded = info.is_loaded ? 1 : 0; 1181 address = info.address; 1182 load_time = Time::Now().ToInternalValue(); 1183 1184 bool success = changes.compare_exchange_strong(new_changes, old_changes + 1, 1185 std::memory_order_release, 1186 std::memory_order_relaxed); 1187 DCHECK(success); 1188 return true; 1189 } 1190 1191 GlobalActivityTracker::ScopedThreadActivity::ScopedThreadActivity( 1192 const void* program_counter, 1193 const void* origin, 1194 Activity::Type type, 1195 const ActivityData& data, 1196 bool lock_allowed) 1197 : ThreadActivityTracker::ScopedActivity(GetOrCreateTracker(lock_allowed), 1198 program_counter, 1199 origin, 1200 type, 1201 data) {} 1202 1203 GlobalActivityTracker::ScopedThreadActivity::~ScopedThreadActivity() { 1204 if (tracker_ && tracker_->HasUserData(activity_id_)) { 1205 GlobalActivityTracker* global = GlobalActivityTracker::Get(); 1206 AutoLock lock(global->user_data_allocator_lock_); 1207 tracker_->ReleaseUserData(activity_id_, &global->user_data_allocator_); 1208 } 1209 } 1210 1211 ActivityUserData& GlobalActivityTracker::ScopedThreadActivity::user_data() { 1212 if (!user_data_) { 1213 if (tracker_) { 1214 GlobalActivityTracker* global = GlobalActivityTracker::Get(); 1215 AutoLock lock(global->user_data_allocator_lock_); 1216 user_data_ = 1217 tracker_->GetUserData(activity_id_, &global->user_data_allocator_); 1218 } else { 1219 user_data_ = std::make_unique<ActivityUserData>(); 1220 } 1221 } 1222 return *user_data_; 1223 } 1224 1225 GlobalActivityTracker::ThreadSafeUserData::ThreadSafeUserData(void* memory, 1226 size_t size, 1227 int64_t pid) 1228 : ActivityUserData(memory, size, pid) {} 1229 1230 GlobalActivityTracker::ThreadSafeUserData::~ThreadSafeUserData() = default; 1231 1232 void GlobalActivityTracker::ThreadSafeUserData::Set(StringPiece name, 1233 ValueType type, 1234 const void* memory, 1235 size_t size) { 1236 AutoLock lock(data_lock_); 1237 ActivityUserData::Set(name, type, memory, size); 1238 } 1239 1240 GlobalActivityTracker::ManagedActivityTracker::ManagedActivityTracker( 1241 PersistentMemoryAllocator::Reference mem_reference, 1242 void* base, 1243 size_t size) 1244 : ThreadActivityTracker(base, size), 1245 mem_reference_(mem_reference), 1246 mem_base_(base) {} 1247 1248 GlobalActivityTracker::ManagedActivityTracker::~ManagedActivityTracker() { 1249 // The global |g_tracker_| must point to the owner of this class since all 1250 // objects of this type must be destructed before |g_tracker_| can be changed 1251 // (something that only occurs in tests). 1252 DCHECK(g_tracker_); 1253 GlobalActivityTracker::Get()->ReturnTrackerMemory(this); 1254 } 1255 1256 void GlobalActivityTracker::CreateWithAllocator( 1257 std::unique_ptr<PersistentMemoryAllocator> allocator, 1258 int stack_depth, 1259 int64_t process_id) { 1260 // There's no need to do anything with the result. It is self-managing. 1261 GlobalActivityTracker* global_tracker = 1262 new GlobalActivityTracker(std::move(allocator), stack_depth, process_id); 1263 // Create a tracker for this thread since it is known. 1264 global_tracker->CreateTrackerForCurrentThread(); 1265 } 1266 1267 #if !defined(OS_NACL) 1268 // static 1269 bool GlobalActivityTracker::CreateWithFile(const FilePath& file_path, 1270 size_t size, 1271 uint64_t id, 1272 StringPiece name, 1273 int stack_depth) { 1274 DCHECK(!file_path.empty()); 1275 DCHECK_GE(static_cast<uint64_t>(std::numeric_limits<int64_t>::max()), size); 1276 1277 // Create and map the file into memory and make it globally available. 1278 std::unique_ptr<MemoryMappedFile> mapped_file(new MemoryMappedFile()); 1279 bool success = mapped_file->Initialize( 1280 File(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_READ | 1281 File::FLAG_WRITE | File::FLAG_SHARE_DELETE), 1282 {0, size}, MemoryMappedFile::READ_WRITE_EXTEND); 1283 if (!success) 1284 return false; 1285 if (!FilePersistentMemoryAllocator::IsFileAcceptable(*mapped_file, false)) 1286 return false; 1287 CreateWithAllocator(std::make_unique<FilePersistentMemoryAllocator>( 1288 std::move(mapped_file), size, id, name, false), 1289 stack_depth, 0); 1290 return true; 1291 } 1292 #endif // !defined(OS_NACL) 1293 1294 // static 1295 bool GlobalActivityTracker::CreateWithLocalMemory(size_t size, 1296 uint64_t id, 1297 StringPiece name, 1298 int stack_depth, 1299 int64_t process_id) { 1300 CreateWithAllocator( 1301 std::make_unique<LocalPersistentMemoryAllocator>(size, id, name), 1302 stack_depth, process_id); 1303 return true; 1304 } 1305 1306 // static 1307 bool GlobalActivityTracker::CreateWithSharedMemory( 1308 std::unique_ptr<SharedMemory> shm, 1309 uint64_t id, 1310 StringPiece name, 1311 int stack_depth) { 1312 if (shm->mapped_size() == 0 || 1313 !SharedPersistentMemoryAllocator::IsSharedMemoryAcceptable(*shm)) { 1314 return false; 1315 } 1316 CreateWithAllocator(std::make_unique<SharedPersistentMemoryAllocator>( 1317 std::move(shm), id, name, false), 1318 stack_depth, 0); 1319 return true; 1320 } 1321 1322 // static 1323 bool GlobalActivityTracker::CreateWithSharedMemoryHandle( 1324 const SharedMemoryHandle& handle, 1325 size_t size, 1326 uint64_t id, 1327 StringPiece name, 1328 int stack_depth) { 1329 std::unique_ptr<SharedMemory> shm( 1330 new SharedMemory(handle, /*readonly=*/false)); 1331 if (!shm->Map(size)) 1332 return false; 1333 return CreateWithSharedMemory(std::move(shm), id, name, stack_depth); 1334 } 1335 1336 // static 1337 void GlobalActivityTracker::SetForTesting( 1338 std::unique_ptr<GlobalActivityTracker> tracker) { 1339 CHECK(!subtle::NoBarrier_Load(&g_tracker_)); 1340 subtle::Release_Store(&g_tracker_, 1341 reinterpret_cast<uintptr_t>(tracker.release())); 1342 } 1343 1344 // static 1345 std::unique_ptr<GlobalActivityTracker> 1346 GlobalActivityTracker::ReleaseForTesting() { 1347 GlobalActivityTracker* tracker = Get(); 1348 if (!tracker) 1349 return nullptr; 1350 1351 // Thread trackers assume that the global tracker is present for some 1352 // operations so ensure that there aren't any. 1353 tracker->ReleaseTrackerForCurrentThreadForTesting(); 1354 DCHECK_EQ(0, tracker->thread_tracker_count_.load(std::memory_order_relaxed)); 1355 1356 subtle::Release_Store(&g_tracker_, 0); 1357 return WrapUnique(tracker); 1358 } 1359 1360 ThreadActivityTracker* GlobalActivityTracker::CreateTrackerForCurrentThread() { 1361 DCHECK(!this_thread_tracker_.Get()); 1362 1363 PersistentMemoryAllocator::Reference mem_reference; 1364 1365 { 1366 base::AutoLock autolock(thread_tracker_allocator_lock_); 1367 mem_reference = thread_tracker_allocator_.GetObjectReference(); 1368 } 1369 1370 if (!mem_reference) { 1371 // Failure. This shouldn't happen. But be graceful if it does, probably 1372 // because the underlying allocator wasn't given enough memory to satisfy 1373 // to all possible requests. 1374 NOTREACHED(); 1375 // Report the thread-count at which the allocator was full so that the 1376 // failure can be seen and underlying memory resized appropriately. 1377 UMA_HISTOGRAM_COUNTS_1000( 1378 "ActivityTracker.ThreadTrackers.MemLimitTrackerCount", 1379 thread_tracker_count_.load(std::memory_order_relaxed)); 1380 // Return null, just as if tracking wasn't enabled. 1381 return nullptr; 1382 } 1383 1384 // Convert the memory block found above into an actual memory address. 1385 // Doing the conversion as a Header object enacts the 32/64-bit size 1386 // consistency checks which would not otherwise be done. Unfortunately, 1387 // some older compilers and MSVC don't have standard-conforming definitions 1388 // of std::atomic which cause it not to be plain-old-data. Don't check on 1389 // those platforms assuming that the checks on other platforms will be 1390 // sufficient. 1391 // TODO(bcwhite): Review this after major compiler releases. 1392 DCHECK(mem_reference); 1393 void* mem_base; 1394 mem_base = 1395 allocator_->GetAsObject<ThreadActivityTracker::Header>(mem_reference); 1396 1397 DCHECK(mem_base); 1398 DCHECK_LE(stack_memory_size_, allocator_->GetAllocSize(mem_reference)); 1399 1400 // Create a tracker with the acquired memory and set it as the tracker 1401 // for this particular thread in thread-local-storage. 1402 ManagedActivityTracker* tracker = 1403 new ManagedActivityTracker(mem_reference, mem_base, stack_memory_size_); 1404 DCHECK(tracker->IsValid()); 1405 this_thread_tracker_.Set(tracker); 1406 int old_count = thread_tracker_count_.fetch_add(1, std::memory_order_relaxed); 1407 1408 UMA_HISTOGRAM_EXACT_LINEAR("ActivityTracker.ThreadTrackers.Count", 1409 old_count + 1, static_cast<int>(kMaxThreadCount)); 1410 return tracker; 1411 } 1412 1413 void GlobalActivityTracker::ReleaseTrackerForCurrentThreadForTesting() { 1414 ThreadActivityTracker* tracker = 1415 reinterpret_cast<ThreadActivityTracker*>(this_thread_tracker_.Get()); 1416 if (tracker) { 1417 this_thread_tracker_.Set(nullptr); 1418 delete tracker; 1419 } 1420 } 1421 1422 void GlobalActivityTracker::SetBackgroundTaskRunner( 1423 const scoped_refptr<TaskRunner>& runner) { 1424 AutoLock lock(global_tracker_lock_); 1425 background_task_runner_ = runner; 1426 } 1427 1428 void GlobalActivityTracker::SetProcessExitCallback( 1429 ProcessExitCallback callback) { 1430 AutoLock lock(global_tracker_lock_); 1431 process_exit_callback_ = callback; 1432 } 1433 1434 void GlobalActivityTracker::RecordProcessLaunch( 1435 ProcessId process_id, 1436 const FilePath::StringType& cmd) { 1437 const int64_t pid = process_id; 1438 DCHECK_NE(GetProcessId(), pid); 1439 DCHECK_NE(0, pid); 1440 1441 base::AutoLock lock(global_tracker_lock_); 1442 if (base::ContainsKey(known_processes_, pid)) { 1443 // TODO(bcwhite): Measure this in UMA. 1444 NOTREACHED() << "Process #" << process_id 1445 << " was previously recorded as \"launched\"" 1446 << " with no corresponding exit.\n" 1447 << known_processes_[pid]; 1448 known_processes_.erase(pid); 1449 } 1450 1451 #if defined(OS_WIN) 1452 known_processes_.insert(std::make_pair(pid, UTF16ToUTF8(cmd))); 1453 #else 1454 known_processes_.insert(std::make_pair(pid, cmd)); 1455 #endif 1456 } 1457 1458 void GlobalActivityTracker::RecordProcessLaunch( 1459 ProcessId process_id, 1460 const FilePath::StringType& exe, 1461 const FilePath::StringType& args) { 1462 if (exe.find(FILE_PATH_LITERAL(" "))) { 1463 RecordProcessLaunch(process_id, 1464 FilePath::StringType(FILE_PATH_LITERAL("\"")) + exe + 1465 FILE_PATH_LITERAL("\" ") + args); 1466 } else { 1467 RecordProcessLaunch(process_id, exe + FILE_PATH_LITERAL(' ') + args); 1468 } 1469 } 1470 1471 void GlobalActivityTracker::RecordProcessExit(ProcessId process_id, 1472 int exit_code) { 1473 const int64_t pid = process_id; 1474 DCHECK_NE(GetProcessId(), pid); 1475 DCHECK_NE(0, pid); 1476 1477 scoped_refptr<TaskRunner> task_runner; 1478 std::string command_line; 1479 { 1480 base::AutoLock lock(global_tracker_lock_); 1481 task_runner = background_task_runner_; 1482 auto found = known_processes_.find(pid); 1483 if (found != known_processes_.end()) { 1484 command_line = std::move(found->second); 1485 known_processes_.erase(found); 1486 } else { 1487 DLOG(ERROR) << "Recording exit of unknown process #" << process_id; 1488 } 1489 } 1490 1491 // Use the current time to differentiate the process that just exited 1492 // from any that might be created in the future with the same ID. 1493 int64_t now_stamp = Time::Now().ToInternalValue(); 1494 1495 // The persistent allocator is thread-safe so run the iteration and 1496 // adjustments on a worker thread if one was provided. 1497 if (task_runner && !task_runner->RunsTasksInCurrentSequence()) { 1498 task_runner->PostTask( 1499 FROM_HERE, 1500 BindOnce(&GlobalActivityTracker::CleanupAfterProcess, Unretained(this), 1501 pid, now_stamp, exit_code, std::move(command_line))); 1502 return; 1503 } 1504 1505 CleanupAfterProcess(pid, now_stamp, exit_code, std::move(command_line)); 1506 } 1507 1508 void GlobalActivityTracker::SetProcessPhase(ProcessPhase phase) { 1509 process_data().SetInt(kProcessPhaseDataKey, phase); 1510 } 1511 1512 void GlobalActivityTracker::CleanupAfterProcess(int64_t process_id, 1513 int64_t exit_stamp, 1514 int exit_code, 1515 std::string&& command_line) { 1516 // The process may not have exited cleanly so its necessary to go through 1517 // all the data structures it may have allocated in the persistent memory 1518 // segment and mark them as "released". This will allow them to be reused 1519 // later on. 1520 1521 PersistentMemoryAllocator::Iterator iter(allocator_.get()); 1522 PersistentMemoryAllocator::Reference ref; 1523 1524 ProcessExitCallback process_exit_callback; 1525 { 1526 AutoLock lock(global_tracker_lock_); 1527 process_exit_callback = process_exit_callback_; 1528 } 1529 if (process_exit_callback) { 1530 // Find the processes user-data record so the process phase can be passed 1531 // to the callback. 1532 ActivityUserData::Snapshot process_data_snapshot; 1533 while ((ref = iter.GetNextOfType(kTypeIdProcessDataRecord)) != 0) { 1534 const void* memory = allocator_->GetAsArray<char>( 1535 ref, kTypeIdProcessDataRecord, PersistentMemoryAllocator::kSizeAny); 1536 if (!memory) 1537 continue; 1538 int64_t found_id; 1539 int64_t create_stamp; 1540 if (ActivityUserData::GetOwningProcessId(memory, &found_id, 1541 &create_stamp)) { 1542 if (found_id == process_id && create_stamp < exit_stamp) { 1543 const ActivityUserData process_data(const_cast<void*>(memory), 1544 allocator_->GetAllocSize(ref)); 1545 process_data.CreateSnapshot(&process_data_snapshot); 1546 break; // No need to look for any others. 1547 } 1548 } 1549 } 1550 iter.Reset(); // So it starts anew when used below. 1551 1552 // Record the process's phase at exit so callback doesn't need to go 1553 // searching based on a private key value. 1554 ProcessPhase exit_phase = PROCESS_PHASE_UNKNOWN; 1555 auto phase = process_data_snapshot.find(kProcessPhaseDataKey); 1556 if (phase != process_data_snapshot.end()) 1557 exit_phase = static_cast<ProcessPhase>(phase->second.GetInt()); 1558 1559 // Perform the callback. 1560 process_exit_callback.Run(process_id, exit_stamp, exit_code, exit_phase, 1561 std::move(command_line), 1562 std::move(process_data_snapshot)); 1563 } 1564 1565 // Find all allocations associated with the exited process and free them. 1566 uint32_t type; 1567 while ((ref = iter.GetNext(&type)) != 0) { 1568 switch (type) { 1569 case kTypeIdActivityTracker: 1570 case kTypeIdUserDataRecord: 1571 case kTypeIdProcessDataRecord: 1572 case ModuleInfoRecord::kPersistentTypeId: { 1573 const void* memory = allocator_->GetAsArray<char>( 1574 ref, type, PersistentMemoryAllocator::kSizeAny); 1575 if (!memory) 1576 continue; 1577 int64_t found_id; 1578 int64_t create_stamp; 1579 1580 // By convention, the OwningProcess structure is always the first 1581 // field of the structure so there's no need to handle all the 1582 // cases separately. 1583 if (OwningProcess::GetOwningProcessId(memory, &found_id, 1584 &create_stamp)) { 1585 // Only change the type to be "free" if the process ID matches and 1586 // the creation time is before the exit time (so PID re-use doesn't 1587 // cause the erasure of something that is in-use). Memory is cleared 1588 // here, rather than when it's needed, so as to limit the impact at 1589 // that critical time. 1590 if (found_id == process_id && create_stamp < exit_stamp) 1591 allocator_->ChangeType(ref, ~type, type, /*clear=*/true); 1592 } 1593 } break; 1594 } 1595 } 1596 } 1597 1598 void GlobalActivityTracker::RecordLogMessage(StringPiece message) { 1599 // Allocate at least one extra byte so the string is NUL terminated. All 1600 // memory returned by the allocator is guaranteed to be zeroed. 1601 PersistentMemoryAllocator::Reference ref = 1602 allocator_->Allocate(message.size() + 1, kTypeIdGlobalLogMessage); 1603 char* memory = allocator_->GetAsArray<char>(ref, kTypeIdGlobalLogMessage, 1604 message.size() + 1); 1605 if (memory) { 1606 memcpy(memory, message.data(), message.size()); 1607 allocator_->MakeIterable(ref); 1608 } 1609 } 1610 1611 void GlobalActivityTracker::RecordModuleInfo(const ModuleInfo& info) { 1612 AutoLock lock(modules_lock_); 1613 auto found = modules_.find(info.file); 1614 if (found != modules_.end()) { 1615 ModuleInfoRecord* record = found->second; 1616 DCHECK(record); 1617 1618 // Update the basic state of module information that has been already 1619 // recorded. It is assumed that the string information (identifier, 1620 // version, etc.) remain unchanged which means that there's no need 1621 // to create a new record to accommodate a possibly longer length. 1622 record->UpdateFrom(info); 1623 return; 1624 } 1625 1626 ModuleInfoRecord* record = 1627 ModuleInfoRecord::CreateFrom(info, allocator_.get()); 1628 if (!record) 1629 return; 1630 allocator_->MakeIterable(record); 1631 modules_.emplace(info.file, record); 1632 } 1633 1634 void GlobalActivityTracker::RecordFieldTrial(const std::string& trial_name, 1635 StringPiece group_name) { 1636 const std::string key = std::string("FieldTrial.") + trial_name; 1637 process_data_.SetString(key, group_name); 1638 } 1639 1640 void GlobalActivityTracker::RecordException(const void* pc, 1641 const void* origin, 1642 uint32_t code) { 1643 RecordExceptionImpl(pc, origin, code); 1644 } 1645 1646 void GlobalActivityTracker::MarkDeleted() { 1647 allocator_->SetMemoryState(PersistentMemoryAllocator::MEMORY_DELETED); 1648 } 1649 1650 GlobalActivityTracker::GlobalActivityTracker( 1651 std::unique_ptr<PersistentMemoryAllocator> allocator, 1652 int stack_depth, 1653 int64_t process_id) 1654 : allocator_(std::move(allocator)), 1655 stack_memory_size_(ThreadActivityTracker::SizeForStackDepth(stack_depth)), 1656 process_id_(process_id == 0 ? GetCurrentProcId() : process_id), 1657 this_thread_tracker_(&OnTLSDestroy), 1658 thread_tracker_count_(0), 1659 thread_tracker_allocator_(allocator_.get(), 1660 kTypeIdActivityTracker, 1661 kTypeIdActivityTrackerFree, 1662 stack_memory_size_, 1663 kCachedThreadMemories, 1664 /*make_iterable=*/true), 1665 user_data_allocator_(allocator_.get(), 1666 kTypeIdUserDataRecord, 1667 kTypeIdUserDataRecordFree, 1668 kUserDataSize, 1669 kCachedUserDataMemories, 1670 /*make_iterable=*/true), 1671 process_data_(allocator_->GetAsArray<char>( 1672 AllocateFrom(allocator_.get(), 1673 kTypeIdProcessDataRecordFree, 1674 kProcessDataSize, 1675 kTypeIdProcessDataRecord), 1676 kTypeIdProcessDataRecord, 1677 kProcessDataSize), 1678 kProcessDataSize, 1679 process_id_) { 1680 DCHECK_NE(0, process_id_); 1681 1682 // Ensure that there is no other global object and then make this one such. 1683 DCHECK(!g_tracker_); 1684 subtle::Release_Store(&g_tracker_, reinterpret_cast<uintptr_t>(this)); 1685 1686 // The data records must be iterable in order to be found by an analyzer. 1687 allocator_->MakeIterable(allocator_->GetAsReference( 1688 process_data_.GetBaseAddress(), kTypeIdProcessDataRecord)); 1689 1690 // Note that this process has launched. 1691 SetProcessPhase(PROCESS_LAUNCHED); 1692 1693 // Fetch and record all activated field trials. 1694 FieldTrial::ActiveGroups active_groups; 1695 FieldTrialList::GetActiveFieldTrialGroups(&active_groups); 1696 for (auto& group : active_groups) 1697 RecordFieldTrial(group.trial_name, group.group_name); 1698 } 1699 1700 GlobalActivityTracker::~GlobalActivityTracker() { 1701 DCHECK(Get() == nullptr || Get() == this); 1702 DCHECK_EQ(0, thread_tracker_count_.load(std::memory_order_relaxed)); 1703 subtle::Release_Store(&g_tracker_, 0); 1704 } 1705 1706 void GlobalActivityTracker::ReturnTrackerMemory( 1707 ManagedActivityTracker* tracker) { 1708 PersistentMemoryAllocator::Reference mem_reference = tracker->mem_reference_; 1709 void* mem_base = tracker->mem_base_; 1710 DCHECK(mem_reference); 1711 DCHECK(mem_base); 1712 1713 // Remove the destructed tracker from the set of known ones. 1714 DCHECK_LE(1, thread_tracker_count_.load(std::memory_order_relaxed)); 1715 thread_tracker_count_.fetch_sub(1, std::memory_order_relaxed); 1716 1717 // Release this memory for re-use at a later time. 1718 base::AutoLock autolock(thread_tracker_allocator_lock_); 1719 thread_tracker_allocator_.ReleaseObjectReference(mem_reference); 1720 } 1721 1722 void GlobalActivityTracker::RecordExceptionImpl(const void* pc, 1723 const void* origin, 1724 uint32_t code) { 1725 // Get an existing tracker for this thread. It's not possible to create 1726 // one at this point because such would involve memory allocations and 1727 // other potentially complex operations that can cause failures if done 1728 // within an exception handler. In most cases various operations will 1729 // have already created the tracker so this shouldn't generally be a 1730 // problem. 1731 ThreadActivityTracker* tracker = GetTrackerForCurrentThread(); 1732 if (!tracker) 1733 return; 1734 1735 tracker->RecordExceptionActivity(pc, origin, Activity::ACT_EXCEPTION, 1736 ActivityData::ForException(code)); 1737 } 1738 1739 // static 1740 void GlobalActivityTracker::OnTLSDestroy(void* value) { 1741 delete reinterpret_cast<ManagedActivityTracker*>(value); 1742 } 1743 1744 ScopedActivity::ScopedActivity(const void* program_counter, 1745 uint8_t action, 1746 uint32_t id, 1747 int32_t info) 1748 : GlobalActivityTracker::ScopedThreadActivity( 1749 program_counter, 1750 nullptr, 1751 static_cast<Activity::Type>(Activity::ACT_GENERIC | action), 1752 ActivityData::ForGeneric(id, info), 1753 /*lock_allowed=*/true), 1754 id_(id) { 1755 // The action must not affect the category bits of the activity type. 1756 DCHECK_EQ(0, action & Activity::ACT_CATEGORY_MASK); 1757 } 1758 1759 void ScopedActivity::ChangeAction(uint8_t action) { 1760 DCHECK_EQ(0, action & Activity::ACT_CATEGORY_MASK); 1761 ChangeTypeAndData(static_cast<Activity::Type>(Activity::ACT_GENERIC | action), 1762 kNullActivityData); 1763 } 1764 1765 void ScopedActivity::ChangeInfo(int32_t info) { 1766 ChangeTypeAndData(Activity::ACT_NULL, ActivityData::ForGeneric(id_, info)); 1767 } 1768 1769 void ScopedActivity::ChangeActionAndInfo(uint8_t action, int32_t info) { 1770 DCHECK_EQ(0, action & Activity::ACT_CATEGORY_MASK); 1771 ChangeTypeAndData(static_cast<Activity::Type>(Activity::ACT_GENERIC | action), 1772 ActivityData::ForGeneric(id_, info)); 1773 } 1774 1775 ScopedTaskRunActivity::ScopedTaskRunActivity( 1776 const void* program_counter, 1777 const base::PendingTask& task) 1778 : GlobalActivityTracker::ScopedThreadActivity( 1779 program_counter, 1780 task.posted_from.program_counter(), 1781 Activity::ACT_TASK_RUN, 1782 ActivityData::ForTask(task.sequence_num), 1783 /*lock_allowed=*/true) {} 1784 1785 ScopedLockAcquireActivity::ScopedLockAcquireActivity( 1786 const void* program_counter, 1787 const base::internal::LockImpl* lock) 1788 : GlobalActivityTracker::ScopedThreadActivity( 1789 program_counter, 1790 nullptr, 1791 Activity::ACT_LOCK_ACQUIRE, 1792 ActivityData::ForLock(lock), 1793 /*lock_allowed=*/false) {} 1794 1795 ScopedEventWaitActivity::ScopedEventWaitActivity( 1796 const void* program_counter, 1797 const base::WaitableEvent* event) 1798 : GlobalActivityTracker::ScopedThreadActivity( 1799 program_counter, 1800 nullptr, 1801 Activity::ACT_EVENT_WAIT, 1802 ActivityData::ForEvent(event), 1803 /*lock_allowed=*/true) {} 1804 1805 ScopedThreadJoinActivity::ScopedThreadJoinActivity( 1806 const void* program_counter, 1807 const base::PlatformThreadHandle* thread) 1808 : GlobalActivityTracker::ScopedThreadActivity( 1809 program_counter, 1810 nullptr, 1811 Activity::ACT_THREAD_JOIN, 1812 ActivityData::ForThread(*thread), 1813 /*lock_allowed=*/true) {} 1814 1815 #if !defined(OS_NACL) && !defined(OS_IOS) 1816 ScopedProcessWaitActivity::ScopedProcessWaitActivity( 1817 const void* program_counter, 1818 const base::Process* process) 1819 : GlobalActivityTracker::ScopedThreadActivity( 1820 program_counter, 1821 nullptr, 1822 Activity::ACT_PROCESS_WAIT, 1823 ActivityData::ForProcess(process->Pid()), 1824 /*lock_allowed=*/true) {} 1825 #endif 1826 1827 } // namespace debug 1828 } // namespace base 1829