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