thread_id_name_manager.cc 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // Copyright (c) 2012 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. #include "base/threading/thread_id_name_manager.h"
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include "base/check.h"
  8. #include "base/containers/contains.h"
  9. #include "base/containers/cxx20_erase.h"
  10. #include "base/memory/singleton.h"
  11. #include "base/no_destructor.h"
  12. #include "base/strings/string_util.h"
  13. #include "base/threading/thread_local.h"
  14. #include "base/trace_event/heap_profiler_allocation_context_tracker.h" // no-presubmit-check
  15. namespace base {
  16. namespace {
  17. static const char kDefaultName[] = "";
  18. static std::string* g_default_name;
  19. ThreadLocalStorage::Slot& GetThreadNameTLS() {
  20. static base::NoDestructor<base::ThreadLocalStorage::Slot> thread_name_tls;
  21. return *thread_name_tls;
  22. }
  23. }
  24. ThreadIdNameManager::Observer::~Observer() = default;
  25. ThreadIdNameManager::ThreadIdNameManager()
  26. : main_process_name_(nullptr), main_process_id_(kInvalidThreadId) {
  27. g_default_name = new std::string(kDefaultName);
  28. AutoLock locked(lock_);
  29. name_to_interned_name_[kDefaultName] = g_default_name;
  30. }
  31. ThreadIdNameManager::~ThreadIdNameManager() = default;
  32. ThreadIdNameManager* ThreadIdNameManager::GetInstance() {
  33. return Singleton<ThreadIdNameManager,
  34. LeakySingletonTraits<ThreadIdNameManager> >::get();
  35. }
  36. const char* ThreadIdNameManager::GetDefaultInternedString() {
  37. return g_default_name->c_str();
  38. }
  39. void ThreadIdNameManager::RegisterThread(PlatformThreadHandle::Handle handle,
  40. PlatformThreadId id) {
  41. AutoLock locked(lock_);
  42. thread_id_to_handle_[id] = handle;
  43. thread_handle_to_interned_name_[handle] =
  44. name_to_interned_name_[kDefaultName];
  45. }
  46. void ThreadIdNameManager::AddObserver(Observer* obs) {
  47. AutoLock locked(lock_);
  48. DCHECK(!base::Contains(observers_, obs));
  49. observers_.push_back(obs);
  50. }
  51. void ThreadIdNameManager::RemoveObserver(Observer* obs) {
  52. AutoLock locked(lock_);
  53. DCHECK(base::Contains(observers_, obs));
  54. base::Erase(observers_, obs);
  55. }
  56. void ThreadIdNameManager::SetName(const std::string& name) {
  57. PlatformThreadId id = PlatformThread::CurrentId();
  58. std::string* leaked_str = nullptr;
  59. {
  60. AutoLock locked(lock_);
  61. auto iter = name_to_interned_name_.find(name);
  62. if (iter != name_to_interned_name_.end()) {
  63. leaked_str = iter->second;
  64. } else {
  65. leaked_str = new std::string(name);
  66. name_to_interned_name_[name] = leaked_str;
  67. }
  68. auto id_to_handle_iter = thread_id_to_handle_.find(id);
  69. GetThreadNameTLS().Set(const_cast<char*>(leaked_str->c_str()));
  70. for (Observer* obs : observers_)
  71. obs->OnThreadNameChanged(leaked_str->c_str());
  72. // The main thread of a process will not be created as a Thread object which
  73. // means there is no PlatformThreadHandler registered.
  74. if (id_to_handle_iter == thread_id_to_handle_.end()) {
  75. main_process_name_ = leaked_str;
  76. main_process_id_ = id;
  77. return;
  78. }
  79. thread_handle_to_interned_name_[id_to_handle_iter->second] = leaked_str;
  80. }
  81. // Add the leaked thread name to heap profiler context tracker. The name added
  82. // is valid for the lifetime of the process. AllocationContextTracker cannot
  83. // call GetName(which holds a lock) during the first allocation because it can
  84. // cause a deadlock when the first allocation happens in the
  85. // ThreadIdNameManager itself when holding the lock.
  86. trace_event::AllocationContextTracker::SetCurrentThreadName(
  87. leaked_str->c_str());
  88. }
  89. const char* ThreadIdNameManager::GetName(PlatformThreadId id) {
  90. AutoLock locked(lock_);
  91. if (id == main_process_id_)
  92. return main_process_name_->c_str();
  93. auto id_to_handle_iter = thread_id_to_handle_.find(id);
  94. if (id_to_handle_iter == thread_id_to_handle_.end())
  95. return name_to_interned_name_[kDefaultName]->c_str();
  96. auto handle_to_name_iter =
  97. thread_handle_to_interned_name_.find(id_to_handle_iter->second);
  98. return handle_to_name_iter->second->c_str();
  99. }
  100. const char* ThreadIdNameManager::GetNameForCurrentThread() {
  101. const char* name = reinterpret_cast<const char*>(GetThreadNameTLS().Get());
  102. return name ? name : kDefaultName;
  103. }
  104. void ThreadIdNameManager::RemoveName(PlatformThreadHandle::Handle handle,
  105. PlatformThreadId id) {
  106. AutoLock locked(lock_);
  107. auto handle_to_name_iter = thread_handle_to_interned_name_.find(handle);
  108. DCHECK(handle_to_name_iter != thread_handle_to_interned_name_.end());
  109. thread_handle_to_interned_name_.erase(handle_to_name_iter);
  110. auto id_to_handle_iter = thread_id_to_handle_.find(id);
  111. DCHECK((id_to_handle_iter!= thread_id_to_handle_.end()));
  112. // The given |id| may have been re-used by the system. Make sure the
  113. // mapping points to the provided |handle| before removal.
  114. if (id_to_handle_iter->second != handle)
  115. return;
  116. thread_id_to_handle_.erase(id_to_handle_iter);
  117. }
  118. std::vector<PlatformThreadId> ThreadIdNameManager::GetIds() {
  119. AutoLock locked(lock_);
  120. std::vector<PlatformThreadId> ids;
  121. ids.reserve(thread_id_to_handle_.size());
  122. for (const auto& iter : thread_id_to_handle_)
  123. ids.push_back(iter.first);
  124. return ids;
  125. }
  126. } // namespace base