summaryrefslogtreecommitdiffstats
path: root/base/threading
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/threading
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/threading')
-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
7 files changed, 233 insertions, 37 deletions
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