Home | History | Annotate | Download | only in threading
      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 
     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 
     32 ThreadIdNameManager::~ThreadIdNameManager() {
     33 }
     34 
     35 ThreadIdNameManager* ThreadIdNameManager::GetInstance() {
     36   return Singleton<ThreadIdNameManager,
     37       LeakySingletonTraits<ThreadIdNameManager> >::get();
     38 }
     39 
     40 const char* ThreadIdNameManager::GetDefaultInternedString() {
     41   return g_default_name->c_str();
     42 }
     43 
     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 
     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 
     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 
    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