• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()23 ThreadIdNameManager::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()32 ThreadIdNameManager::~ThreadIdNameManager() {
33 }
34 
GetInstance()35 ThreadIdNameManager* ThreadIdNameManager::GetInstance() {
36   return Singleton<ThreadIdNameManager,
37       LeakySingletonTraits<ThreadIdNameManager> >::get();
38 }
39 
GetDefaultInternedString()40 const char* ThreadIdNameManager::GetDefaultInternedString() {
41   return g_default_name->c_str();
42 }
43 
RegisterThread(PlatformThreadHandle::Handle handle,PlatformThreadId id)44 void 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)52 void 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)87 const 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)103 void 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