summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authordsinclair@chromium.org <dsinclair@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-25 20:41:19 +0000
committerdsinclair@chromium.org <dsinclair@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-25 20:41:19 +0000
commit7d342e882772e35c4e60e640f3501a84fd0a5bec (patch)
treecb86e79488437edcd41452488555cace9a628ca4 /base
parent02fd1dc91b2a4741356ed3a9694fcf977f6beda6 (diff)
downloadchromium_src-7d342e882772e35c4e60e640f3501a84fd0a5bec.zip
chromium_src-7d342e882772e35c4e60e640f3501a84fd0a5bec.tar.gz
chromium_src-7d342e882772e35c4e60e640f3501a84fd0a5bec.tar.bz2
Add ability to retrieve a thread_name given a thread_id.
The work to add GPU tracing needs the ability to map from a thread_id back to a thread_name in order to allow us to have the correct display on the chrome://tracing page. We want to be able to output our traces without having to post to a thread to handle the output, and to have the GPU traces differentiated from the GPU-process which will be doing the tracing calls. BUG=111509 TEST=Added tests in base_unittests Review URL: https://chromiumcodereview.appspot.com/11438022 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@178886 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r--base/base.gyp3
-rw-r--r--base/base.gypi2
-rw-r--r--base/debug/trace_event_impl.cc4
-rw-r--r--base/debug/trace_event_unittest.cc9
-rw-r--r--base/threading/platform_thread_mac.mm16
-rw-r--r--base/threading/platform_thread_posix.cc22
-rw-r--r--base/threading/platform_thread_win.cc8
-rw-r--r--base/threading/thread.cc2
-rw-r--r--base/threading/thread_id_name_manager.cc79
-rw-r--r--base/threading/thread_id_name_manager.h52
-rw-r--r--base/threading/thread_id_name_manager_unittest.cc91
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