diff options
-rw-r--r-- | base/base.gyp | 3 | ||||
-rw-r--r-- | base/base.gypi | 2 | ||||
-rw-r--r-- | base/debug/trace_event_impl.cc | 4 | ||||
-rw-r--r-- | base/debug/trace_event_unittest.cc | 9 | ||||
-rw-r--r-- | base/threading/platform_thread_mac.mm | 16 | ||||
-rw-r--r-- | base/threading/platform_thread_posix.cc | 22 | ||||
-rw-r--r-- | base/threading/platform_thread_win.cc | 8 | ||||
-rw-r--r-- | base/threading/thread.cc | 2 | ||||
-rw-r--r-- | base/threading/thread_id_name_manager.cc | 79 | ||||
-rw-r--r-- | base/threading/thread_id_name_manager.h | 52 | ||||
-rw-r--r-- | base/threading/thread_id_name_manager_unittest.cc | 91 |
11 files changed, 246 insertions, 42 deletions
diff --git a/base/base.gyp b/base/base.gyp index efb94ef..f963cc2 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -338,8 +338,8 @@ 'prefs/overlay_user_pref_store.cc', 'prefs/overlay_user_pref_store.h', 'prefs/persistent_pref_store.h', - 'prefs/pref_observer.h', 'prefs/pref_notifier.h', + 'prefs/pref_observer.h', 'prefs/pref_store.cc', 'prefs/pref_store.h', 'prefs/pref_value_map.cc', @@ -552,6 +552,7 @@ 'threading/simple_thread_unittest.cc', 'threading/thread_checker_unittest.cc', 'threading/thread_collision_warner_unittest.cc', + 'threading/thread_id_name_manager_unittest.cc', 'threading/thread_local_storage_unittest.cc', 'threading/thread_local_unittest.cc', 'threading/thread_unittest.cc', diff --git a/base/base.gypi b/base/base.gypi index 17b7629..b0d39a7 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -468,6 +468,8 @@ 'threading/thread_checker_impl.h', 'threading/thread_collision_warner.cc', 'threading/thread_collision_warner.h', + 'threading/thread_id_name_manager.cc', + 'threading/thread_id_name_manager.h', 'threading/thread_local.h', 'threading/thread_local_posix.cc', 'threading/thread_local_storage.h', diff --git a/base/debug/trace_event_impl.cc b/base/debug/trace_event_impl.cc index e85db1d..411da1d 100644 --- a/base/debug/trace_event_impl.cc +++ b/base/debug/trace_event_impl.cc @@ -65,7 +65,9 @@ const int g_category_categories_exhausted = 1; const int g_category_metadata = 2; int g_category_index = 3; // skip initial 3 categories -// The most-recently captured name of the current thread +// The name of the current thread. This is used to decide if the current +// thread name has changed. We combine all the seen thread names into the +// output name for the thread. LazyInstance<ThreadLocalPointer<const char> >::Leaky g_current_thread_name = LAZY_INSTANCE_INITIALIZER; diff --git a/base/debug/trace_event_unittest.cc b/base/debug/trace_event_unittest.cc index cf16fa5..c42cc5d 100644 --- a/base/debug/trace_event_unittest.cc +++ b/base/debug/trace_event_unittest.cc @@ -79,15 +79,18 @@ class TraceEventTestFixture : public testing::Test { } virtual void SetUp() OVERRIDE { - old_thread_name_ = PlatformThread::GetName(); + const char* name = PlatformThread::GetName(); + old_thread_name_ = name ? strdup(name) : NULL; } virtual void TearDown() OVERRIDE { if (TraceLog::GetInstance()) EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled()); - PlatformThread::SetName(old_thread_name_ ? old_thread_name_ : ""); + PlatformThread::SetName(old_thread_name_ ? old_thread_name_ : ""); + free(old_thread_name_); + old_thread_name_ = NULL; } - const char* old_thread_name_; + char* old_thread_name_; ListValue trace_parsed_; base::debug::TraceResultBuffer trace_buffer_; base::debug::TraceResultBuffer::SimpleOutput json_output_; diff --git a/base/threading/platform_thread_mac.mm b/base/threading/platform_thread_mac.mm index 96c6720..48041a0 100644 --- a/base/threading/platform_thread_mac.mm +++ b/base/threading/platform_thread_mac.mm @@ -12,18 +12,11 @@ #include "base/lazy_instance.h" #include "base/logging.h" -#include "base/threading/thread_local.h" +#include "base/threading/thread_id_name_manager.h" #include "base/tracked_objects.h" namespace base { -namespace { - -LazyInstance<ThreadLocalPointer<char> >::Leaky - current_thread_name = LAZY_INSTANCE_INITIALIZER; - -} // namespace - // If Cocoa is to be used on more than one thread, it must know that the // application is multithreaded. Since it's possible to enter Cocoa code // from threads created by pthread_thread_create, Cocoa won't necessarily @@ -47,7 +40,7 @@ void InitThreading() { // static void PlatformThread::SetName(const char* name) { - current_thread_name.Pointer()->Set(const_cast<char*>(name)); + ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name); tracked_objects::ThreadData::InitializeThreadContext(name); // pthread_setname_np is only available in 10.6 or later, so test @@ -67,11 +60,6 @@ void PlatformThread::SetName(const char* name) { dynamic_pthread_setname_np(shortened_name.c_str()); } -// static -const char* PlatformThread::GetName() { - return current_thread_name.Pointer()->Get(); -} - namespace { void SetPriorityNormal(mach_port_t mach_thread_id) { diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc index 0a6741c..13ca87c 100644 --- a/base/threading/platform_thread_posix.cc +++ b/base/threading/platform_thread_posix.cc @@ -11,7 +11,7 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/safe_strerror_posix.h" -#include "base/threading/thread_local.h" +#include "base/threading/thread_id_name_manager.h" #include "base/threading/thread_restrictions.h" #include "base/tracked_objects.h" @@ -46,12 +46,6 @@ void InitThreading(); namespace { -#if !defined(OS_MACOSX) -// Mac name code is in in platform_thread_mac.mm. -LazyInstance<ThreadLocalPointer<char> >::Leaky - current_thread_name = LAZY_INSTANCE_INITIALIZER; -#endif - struct ThreadParams { PlatformThread::Delegate* delegate; bool joinable; @@ -205,9 +199,7 @@ void PlatformThread::Sleep(TimeDelta duration) { #if defined(OS_LINUX) // static void PlatformThread::SetName(const char* name) { - // have to cast away const because ThreadLocalPointer does not support const - // void* - current_thread_name.Pointer()->Set(const_cast<char*>(name)); + ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name); tracked_objects::ThreadData::InitializeThreadContext(name); // On linux we can get the thread names to show up in the debugger by setting @@ -232,9 +224,7 @@ void PlatformThread::SetName(const char* name) { #else // static void PlatformThread::SetName(const char* name) { - // have to cast away const because ThreadLocalPointer does not support const - // void* - current_thread_name.Pointer()->Set(const_cast<char*>(name)); + ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name); tracked_objects::ThreadData::InitializeThreadContext(name); // (This should be relatively simple to implement for the BSDs; I @@ -242,14 +232,10 @@ void PlatformThread::SetName(const char* name) { } #endif // defined(OS_LINUX) - -#if !defined(OS_MACOSX) -// Mac is implemented in platform_thread_mac.mm. // static const char* PlatformThread::GetName() { - return current_thread_name.Pointer()->Get(); + return ThreadIdNameManager::GetInstance()->GetName(CurrentId()); } -#endif // static bool PlatformThread::Create(size_t stack_size, Delegate* delegate, diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc index 82981ad..9e877b3 100644 --- a/base/threading/platform_thread_win.cc +++ b/base/threading/platform_thread_win.cc @@ -7,7 +7,7 @@ #include "base/debug/alias.h" #include "base/debug/profiler.h" #include "base/logging.h" -#include "base/threading/thread_local.h" +#include "base/threading/thread_id_name_manager.h" #include "base/threading/thread_restrictions.h" #include "base/tracked_objects.h" @@ -17,8 +17,6 @@ namespace base { namespace { -static ThreadLocalPointer<char> current_thread_name; - // The information on how to set the thread name comes from // a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx const DWORD kVCThreadNameException = 0x406D1388; @@ -116,7 +114,7 @@ void PlatformThread::Sleep(TimeDelta duration) { // static void PlatformThread::SetName(const char* name) { - current_thread_name.Set(const_cast<char*>(name)); + ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name); // On Windows only, we don't need to tell the profiler about the "BrokerEvent" // thread, as it exists only in the chrome.exe image, and never spawns or runs @@ -139,7 +137,7 @@ void PlatformThread::SetName(const char* name) { // static const char* PlatformThread::GetName() { - return current_thread_name.Get(); + return ThreadIdNameManager::GetInstance()->GetName(CurrentId()); } // static diff --git a/base/threading/thread.cc b/base/threading/thread.cc index 8e506ef..35e88a7 100644 --- a/base/threading/thread.cc +++ b/base/threading/thread.cc @@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/lazy_instance.h" #include "base/third_party/dynamic_annotations/dynamic_annotations.h" +#include "base/threading/thread_id_name_manager.h" #include "base/threading/thread_local.h" #include "base/threading/thread_restrictions.h" #include "base/synchronization/waitable_event.h" @@ -65,6 +66,7 @@ Thread::Thread(const char* name) Thread::~Thread() { Stop(); + ThreadIdNameManager::GetInstance()->RemoveName(thread_id_); } bool Thread::Start() { diff --git a/base/threading/thread_id_name_manager.cc b/base/threading/thread_id_name_manager.cc new file mode 100644 index 0000000..5351ba7 --- /dev/null +++ b/base/threading/thread_id_name_manager.cc @@ -0,0 +1,79 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/threading/thread_id_name_manager.h" + +#include <stdlib.h> +#include <string.h> + +#include "base/logging.h" +#include "base/memory/singleton.h" +#include "base/string_util.h" + +namespace base { +namespace { + +static const char kDefaultName[] = ""; +static std::string* g_default_name; + +typedef std::map<PlatformThreadId, std::string*>::iterator + ThreadIdToInternedNameIterator; +typedef std::map<std::string, std::string*>::iterator + NameToInternedNameIterator; +} + +ThreadIdNameManager::ThreadIdNameManager() { + g_default_name = new std::string(kDefaultName); + + AutoLock locked(lock_); + name_to_interned_name_[kDefaultName] = g_default_name; +} + +ThreadIdNameManager::~ThreadIdNameManager() { +} + +ThreadIdNameManager* ThreadIdNameManager::GetInstance() { + return Singleton<ThreadIdNameManager, + LeakySingletonTraits<ThreadIdNameManager> >::get(); +} + +const char* ThreadIdNameManager::GetDefaultInternedString() { + return g_default_name->c_str(); +} + +void ThreadIdNameManager::SetName(PlatformThreadId id, const char* name) { + std::string str_name(name); + + AutoLock locked(lock_); + NameToInternedNameIterator iter = name_to_interned_name_.find(str_name); + std::string* leaked_str = NULL; + if (iter != name_to_interned_name_.end()) { + leaked_str = iter->second; + } else { + leaked_str = new std::string(str_name); + name_to_interned_name_[str_name] = leaked_str; + } + thread_id_to_interned_name_[id] = leaked_str; +} + +const char* ThreadIdNameManager::GetName(PlatformThreadId id) { + AutoLock locked(lock_); + ThreadIdToInternedNameIterator iter = thread_id_to_interned_name_.find(id); + // A platform thread may not have a name set, so return blank. + if (iter == thread_id_to_interned_name_.end()) + return name_to_interned_name_[kDefaultName]->c_str(); + return iter->second->c_str(); +} + +void ThreadIdNameManager::RemoveName(PlatformThreadId id) { + if (id == kInvalidThreadId) + return; + + AutoLock locked(lock_); + ThreadIdToInternedNameIterator iter = thread_id_to_interned_name_.find(id); + DCHECK((iter != thread_id_to_interned_name_.end())); + thread_id_to_interned_name_.erase(iter); +} + +} // namespace base diff --git a/base/threading/thread_id_name_manager.h b/base/threading/thread_id_name_manager.h new file mode 100644 index 0000000..e592742 --- /dev/null +++ b/base/threading/thread_id_name_manager.h @@ -0,0 +1,52 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_THREADING_THREAD_ID_NAME_MANAGER_H_ +#define BASE_THREADING_THREAD_ID_NAME_MANAGER_H_ + +#include <map> +#include <string> + +#include "base/base_export.h" +#include "base/basictypes.h" +#include "base/synchronization/lock.h" +#include "base/threading/platform_thread.h" + +template <typename T> struct DefaultSingletonTraits; + +namespace base { + +class BASE_EXPORT ThreadIdNameManager { + public: + static ThreadIdNameManager* GetInstance(); + + static const char* GetDefaultInternedString(); + + // Set the name for the given id. + void SetName(PlatformThreadId id, const char* name); + + // Get the name for the given id. + const char* GetName(PlatformThreadId id); + + // Remove the name for the given id. + void RemoveName(PlatformThreadId id); + + private: + friend struct DefaultSingletonTraits<ThreadIdNameManager>; + + ThreadIdNameManager(); + ~ThreadIdNameManager(); + + // lock_ protects both the thread_id_to_name_ and name_to_interned_name_ maps. + Lock lock_; + + std::map<PlatformThreadId, std::string*> thread_id_to_interned_name_; + std::map<std::string, std::string*> name_to_interned_name_; + + DISALLOW_COPY_AND_ASSIGN(ThreadIdNameManager); +}; + +} // namespace base + +#endif // BASE_THREADING_THREAD_ID_NAME_MANAGER_H_ diff --git a/base/threading/thread_id_name_manager_unittest.cc b/base/threading/thread_id_name_manager_unittest.cc new file mode 100644 index 0000000..08f1ea7 --- /dev/null +++ b/base/threading/thread_id_name_manager_unittest.cc @@ -0,0 +1,91 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/threading/thread_id_name_manager.h" + +#include "base/threading/platform_thread.h" +#include "base/threading/thread.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/platform_test.h" + +typedef PlatformTest ThreadIdNameManagerTest; + +namespace { + +static const char* kAThread = "a thread"; +static const char* kBThread = "b thread"; + +TEST_F(ThreadIdNameManagerTest, AddThreads) { + base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance(); + base::Thread thread_a(kAThread); + base::Thread thread_b(kBThread); + + thread_a.Start(); + thread_b.Start(); + + EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id())); + EXPECT_STREQ(kBThread, manager->GetName(thread_b.thread_id())); + + thread_b.Stop(); + thread_a.Stop(); +} + +TEST_F(ThreadIdNameManagerTest, RemoveThreads) { + base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance(); + base::Thread thread_a(kAThread); + + thread_a.Start(); + { + base::Thread thread_b(kBThread); + thread_b.Start(); + thread_b.Stop(); + } + thread_a.Stop(); + + EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id())); +} + +TEST_F(ThreadIdNameManagerTest, RestartThread) { + base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance(); + base::Thread thread_a(kAThread); + + thread_a.Start(); + base::PlatformThreadId a_id = thread_a.thread_id(); + thread_a.Stop(); + EXPECT_STREQ(kAThread, manager->GetName(a_id)); + + thread_a.Start(); + thread_a.Stop(); + EXPECT_STREQ(kAThread, manager->GetName(a_id)); +} + +TEST_F(ThreadIdNameManagerTest, ThreadNameInterning) { + base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance(); + + base::PlatformThreadId a_id = base::PlatformThread::CurrentId(); + base::PlatformThread::SetName("First Name"); + std::string version = manager->GetName(a_id); + + base::PlatformThread::SetName("New name"); + EXPECT_NE(version, manager->GetName(a_id)); + base::PlatformThread::SetName(""); +} + +TEST_F(ThreadIdNameManagerTest, ResettingNameKeepsCorrectInternedValue) { + base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance(); + + base::PlatformThreadId a_id = base::PlatformThread::CurrentId(); + base::PlatformThread::SetName("Test Name"); + std::string version = manager->GetName(a_id); + + base::PlatformThread::SetName("New name"); + EXPECT_NE(version, manager->GetName(a_id)); + + base::PlatformThread::SetName("Test Name"); + EXPECT_EQ(version, manager->GetName(a_id)); + + base::PlatformThread::SetName(""); +} + +} // namespace |