diff options
author | evanm@google.com <evanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-20 22:54:52 +0000 |
---|---|---|
committer | evanm@google.com <evanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-20 22:54:52 +0000 |
commit | 6a6e657234868ad4044b03bdeb9c6f7e872b5ee6 (patch) | |
tree | 36d9855863e1cf5615b62623b2347ec494447cdb /base | |
parent | 15e8abe105f4c2a08cd5dc51e95ec1791ac440f2 (diff) | |
download | chromium_src-6a6e657234868ad4044b03bdeb9c6f7e872b5ee6.zip chromium_src-6a6e657234868ad4044b03bdeb9c6f7e872b5ee6.tar.gz chromium_src-6a6e657234868ad4044b03bdeb9c6f7e872b5ee6.tar.bz2 |
TrackedObjects assumes you can use a "TLS slot" of -1 to indicate uninitialized. This isn't true for the pthread_key_t type, which is unsigned on Linux and reportedly a struct on Macs. This change modifies the Slot type to be a struct containing an "initialized" flag.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@1122 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/message_loop.cc | 8 | ||||
-rw-r--r-- | base/message_loop.h | 2 | ||||
-rw-r--r-- | base/stats_table.cc | 10 | ||||
-rw-r--r-- | base/thread.cc | 8 | ||||
-rw-r--r-- | base/thread_local_storage.h | 81 | ||||
-rw-r--r-- | base/thread_local_storage_posix.cc | 38 | ||||
-rw-r--r-- | base/thread_local_storage_unittest.cc | 16 | ||||
-rw-r--r-- | base/thread_local_storage_win.cc | 53 | ||||
-rw-r--r-- | base/tracked_objects.cc | 25 |
9 files changed, 143 insertions, 98 deletions
diff --git a/base/message_loop.cc b/base/message_loop.cc index caec847..bdf99f0 100644 --- a/base/message_loop.cc +++ b/base/message_loop.cc @@ -39,7 +39,9 @@ // a TLS index to the message loop for the current thread // Note that if we start doing complex stuff in other static initializers // this could cause problems. -/*static*/ TLSSlot MessageLoop::tls_index_ = ThreadLocalStorage::Alloc(); +// TODO(evanm): this shouldn't rely on static initialization. +// static +TLSSlot MessageLoop::tls_index_; //------------------------------------------------------------------------------ @@ -83,7 +85,7 @@ MessageLoop::MessageLoop() exception_restoration_(false), state_(NULL) { DCHECK(!current()) << "should only have one message loop per thread"; - ThreadLocalStorage::Set(tls_index_, this); + tls_index_.Set(this); // TODO(darin): Generalize this to support instantiating different pumps. #if defined(OS_WIN) pump_ = new base::MessagePumpWin(); @@ -100,7 +102,7 @@ MessageLoop::~MessageLoop() { WillDestroyCurrentMessageLoop()); // OK, now make it so that no one can find us. - ThreadLocalStorage::Set(tls_index_, NULL); + tls_index_.Set(NULL); DCHECK(!state_); diff --git a/base/message_loop.h b/base/message_loop.h index 3821519..e11b73f 100644 --- a/base/message_loop.h +++ b/base/message_loop.h @@ -194,7 +194,7 @@ class MessageLoop : public base::MessagePump::Delegate { // Returns the MessageLoop object for the current thread, or null if none. static MessageLoop* current() { - return static_cast<MessageLoop*>(ThreadLocalStorage::Get(tls_index_)); + return static_cast<MessageLoop*>(tls_index_.Get()); } // Returns the TimerManager object for the current thread. diff --git a/base/stats_table.cc b/base/stats_table.cc index 23c736a..8b10662 100644 --- a/base/stats_table.cc +++ b/base/stats_table.cc @@ -254,7 +254,7 @@ StatsTable* StatsTable::global_table_ = NULL; StatsTable::StatsTable(const std::wstring& name, int max_threads, int max_counters) - : tls_index_(ThreadLocalStorage::Alloc(SlotReturnFunction)) { + : tls_index_(SlotReturnFunction) { int table_size = AlignedSize(sizeof(TableHeader)) + AlignedSize((max_counters * sizeof(wchar_t) * kMaxCounterNameLength)) + @@ -285,7 +285,7 @@ StatsTable::~StatsTable() { // Return ThreadLocalStorage. At this point, if any registered threads // still exist, they cannot Unregister. - ThreadLocalStorage::Free(tls_index_); + tls_index_.Free(); // Cleanup our shared memory. delete impl_; @@ -329,13 +329,13 @@ int StatsTable::RegisterThread(const std::wstring& name) { StatsTableTLSData* data = new StatsTableTLSData; data->table = this; data->slot = slot; - ThreadLocalStorage::Set(tls_index_, data); + tls_index_.Set(data); return slot; } StatsTableTLSData* StatsTable::GetTLSData() const { StatsTableTLSData* data = - static_cast<StatsTableTLSData*>(ThreadLocalStorage::Get(tls_index_)); + static_cast<StatsTableTLSData*>(tls_index_.Get()); if (!data) return NULL; @@ -355,7 +355,7 @@ void StatsTable::UnregisterThread() { *name = L'\0'; // Remove the calling thread's TLS so that it cannot use the slot. - ThreadLocalStorage::Set(tls_index_, NULL); + tls_index_.Set(NULL); delete data; } diff --git a/base/thread.cc b/base/thread.cc index 629c7e0..6998deb 100644 --- a/base/thread.cc +++ b/base/thread.cc @@ -69,7 +69,6 @@ Thread::Thread(const char *name) thread_id_(0), message_loop_(NULL), name_(name) { - DCHECK(tls_index_) << "static initializer failed"; } Thread::~Thread() { @@ -82,18 +81,19 @@ Thread::~Thread() { // Thread to setup and run a MessageLoop. // Note that if we start doing complex stuff in other static initializers // this could cause problems. -TLSSlot Thread::tls_index_ = ThreadLocalStorage::Alloc(); +// TODO(evanm): this shouldn't rely on static initialization. +TLSSlot Thread::tls_index_; void Thread::SetThreadWasQuitProperly(bool flag) { #ifndef NDEBUG - ThreadLocalStorage::Set(tls_index_, reinterpret_cast<void*>(flag)); + tls_index_.Set(reinterpret_cast<void*>(flag)); #endif } bool Thread::GetThreadWasQuitProperly() { bool quit_properly = true; #ifndef NDEBUG - quit_properly = (ThreadLocalStorage::Get(tls_index_) != 0); + quit_properly = (tls_index_.Get() != 0); #endif return quit_properly; } diff --git a/base/thread_local_storage.h b/base/thread_local_storage.h index 245a73f..fba90ae 100644 --- a/base/thread_local_storage.h +++ b/base/thread_local_storage.h @@ -32,43 +32,62 @@ #include "base/basictypes.h" -#if defined(OS_WIN) -typedef int TLSSlot; -#elif defined(OS_POSIX) +#if defined(OS_POSIX) #include <pthread.h> -typedef pthread_key_t TLSSlot; -#endif // OS_* +#endif -// Wrapper for thread local storage. This class doesn't -// do much except provide an API for portability later. +// Wrapper for thread local storage. This class doesn't do much except provide +// an API for portability. class ThreadLocalStorage { public: - // Prototype for the TLS destructor function, which can be - // optionally used to cleanup thread local storage on - // thread exit. 'value' is the data that is stored - // in thread local storage. + + // Prototype for the TLS destructor function, which can be optionally used to + // cleanup thread local storage on thread exit. 'value' is the data that is + // stored in thread local storage. typedef void (*TLSDestructorFunc)(void* value); - // Allocate a TLS 'slot'. - // 'destructor' is a pointer to a function to perform - // per-thread cleanup of this object. If set to NULL, - // no cleanup is done for this TLS slot. - // Returns an index > 0 on success, or -1 on failure. - static TLSSlot Alloc(TLSDestructorFunc destructor = NULL); + // A key representing one value stored in TLS. + class Slot { + public: + Slot(TLSDestructorFunc destructor = NULL); + + // This constructor should be used for statics. + // It returns an uninitialized Slot. + explicit Slot(base::LinkerInitialized x) {} + + // Set up the TLS slot. Called by the constructor. + // 'destructor' is a pointer to a function to perform per-thread cleanup of + // this object. If set to NULL, no cleanup is done for this TLS slot. + // Returns false on error. + bool Initialize(TLSDestructorFunc destructor); + + // Free a previously allocated TLS 'slot'. + // If a destructor was set for this slot, removes + // the destructor so that remaining threads exiting + // will not free data. + void Free(); - // Free a previously allocated TLS 'slot'. - // If a destructor was set for this slot, removes - // the destructor so that remaining threads exiting - // will not free data. - static void Free(TLSSlot slot); + // Get the thread-local value stored in slot 'slot'. + // Values are guaranteed to initially be zero. + void* Get() const; - // Get the thread-local value stored in slot 'slot'. - // Values are guaranteed to initially be zero. - static void* Get(TLSSlot slot); + // Set the thread-local value stored in slot 'slot' to + // value 'value'. + void Set(void* value); - // Set the thread-local value stored in slot 'slot' to - // value 'value'. - static void Set(TLSSlot slot, void* value); + bool initialized() const { return initialized_; } + + private: + // The internals of this struct should be considered private. + bool initialized_; +#if defined(OS_WIN) + int slot_; +#elif defined(OS_POSIX) + pthread_key_t key_; +#endif + + DISALLOW_COPY_AND_ASSIGN(Slot); + }; #if defined(OS_WIN) // Function called when on thread exit to call TLS @@ -90,7 +109,11 @@ class ThreadLocalStorage { static TLSDestructorFunc tls_destructors_[kThreadLocalStorageSize]; #endif // OS_WIN - DISALLOW_EVIL_CONSTRUCTORS(ThreadLocalStorage); + DISALLOW_COPY_AND_ASSIGN(ThreadLocalStorage); }; +// Temporary backwards-compatible name. +// TODO(evanm): replace all usage of TLSSlot. +typedef ThreadLocalStorage::Slot TLSSlot; + #endif // BASE_THREAD_LOCAL_STORAGE_H_ diff --git a/base/thread_local_storage_posix.cc b/base/thread_local_storage_posix.cc index bcc982f..7c24e59 100644 --- a/base/thread_local_storage_posix.cc +++ b/base/thread_local_storage_posix.cc @@ -31,23 +31,39 @@ #include "base/logging.h" -TLSSlot ThreadLocalStorage::Alloc(TLSDestructorFunc destructor) { - TLSSlot key; - int error = pthread_key_create(&key, destructor); - if (error) +ThreadLocalStorage::Slot::Slot(TLSDestructorFunc destructor) + : initialized_(false) { + Initialize(destructor); +} + +bool ThreadLocalStorage::Slot::Initialize(TLSDestructorFunc destructor) { + DCHECK(!initialized_); + int error = pthread_key_create(&key_, destructor); + if (error) { NOTREACHED(); + return false; + } - return key; + initialized_ = true; + return true; } -void ThreadLocalStorage::Free(TLSSlot slot) { - pthread_key_delete(slot); +void ThreadLocalStorage::Slot::Free() { + DCHECK(initialized_); + int error = pthread_key_delete(key_); + if (error) + NOTREACHED(); + initialized_ = false; } -void* ThreadLocalStorage::Get(TLSSlot slot) { - return pthread_getspecific(slot); +void* ThreadLocalStorage::Slot::Get() const { + DCHECK(initialized_); + return pthread_getspecific(key_); } -void ThreadLocalStorage::Set(TLSSlot slot, void* value) { - pthread_setspecific(slot, value); +void ThreadLocalStorage::Slot::Set(void* value) { + DCHECK(initialized_); + int error = pthread_setspecific(key_, value); + if (error) + NOTREACHED(); } diff --git a/base/thread_local_storage_unittest.cc b/base/thread_local_storage_unittest.cc index fff0d2a..ba60c2c 100644 --- a/base/thread_local_storage_unittest.cc +++ b/base/thread_local_storage_unittest.cc @@ -44,28 +44,28 @@ namespace { TEST(ThreadLocalStorageTest, Basics) { - int index = ThreadLocalStorage::Alloc(); - ThreadLocalStorage::Set(index, reinterpret_cast<void*>(123)); - int value = reinterpret_cast<int>(ThreadLocalStorage::Get(index)); + ThreadLocalStorage::Slot slot; + slot.Set(reinterpret_cast<void*>(123)); + int value = reinterpret_cast<int>(slot.Get()); EXPECT_EQ(value, 123); } const int kInitialTlsValue = 0x5555; -static int tls_index = 0; +static ThreadLocalStorage::Slot tls_slot(base::LINKER_INITIALIZED); unsigned __stdcall TLSTestThreadMain(void* param) { // param contains the thread local storage index. int *index = reinterpret_cast<int*>(param); *index = kInitialTlsValue; - ThreadLocalStorage::Set(tls_index, index); + tls_slot.Set(index); - int *ptr = static_cast<int*>(ThreadLocalStorage::Get(tls_index)); + int *ptr = static_cast<int*>(tls_slot.Get()); EXPECT_EQ(ptr, index); EXPECT_EQ(*ptr, kInitialTlsValue); *index = 0; - ptr = static_cast<int*>(ThreadLocalStorage::Get(tls_index)); + ptr = static_cast<int*>(tls_slot.Get()); EXPECT_EQ(ptr, index); EXPECT_EQ(*ptr, 0); return 0; @@ -86,7 +86,7 @@ TEST(ThreadLocalStorageTest, TLSDestructors) { HANDLE threads[kNumThreads]; int values[kNumThreads]; - tls_index = ThreadLocalStorage::Alloc(ThreadLocalStorageCleanup); + tls_slot.Initialize(ThreadLocalStorageCleanup); // Spawn the threads. for (int16 index = 0; index < kNumThreads; index++) { diff --git a/base/thread_local_storage_win.cc b/base/thread_local_storage_win.cc index 8157e88..154935a 100644 --- a/base/thread_local_storage_win.cc +++ b/base/thread_local_storage_win.cc @@ -55,7 +55,7 @@ long ThreadLocalStorage::tls_max_ = 1; ThreadLocalStorage::TLSDestructorFunc ThreadLocalStorage::tls_destructors_[kThreadLocalStorageSize]; -void **ThreadLocalStorage::Initialize() { +void** ThreadLocalStorage::Initialize() { if (tls_key_ == TLS_OUT_OF_INDEXES) { long value = TlsAlloc(); DCHECK(value != TLS_OUT_OF_INDEXES); @@ -73,52 +73,59 @@ void **ThreadLocalStorage::Initialize() { DCHECK(TlsGetValue(tls_key_) == NULL); // Create an array to store our data. - void **tls_data = new void*[kThreadLocalStorageSize]; + void** tls_data = new void*[kThreadLocalStorageSize]; memset(tls_data, 0, sizeof(void*[kThreadLocalStorageSize])); TlsSetValue(tls_key_, tls_data); return tls_data; } -TLSSlot ThreadLocalStorage::Alloc(TLSDestructorFunc destructor) { +ThreadLocalStorage::Slot::Slot(TLSDestructorFunc destructor) + : initialized_(false) { + Initialize(destructor); +} + +bool ThreadLocalStorage::Slot::Initialize(TLSDestructorFunc destructor) { if (tls_key_ == TLS_OUT_OF_INDEXES || !TlsGetValue(tls_key_)) - Initialize(); + ThreadLocalStorage::Initialize(); // Grab a new slot. - int slot = InterlockedIncrement(&tls_max_) - 1; - if (slot >= kThreadLocalStorageSize) { + slot_ = InterlockedIncrement(&tls_max_) - 1; + if (slot_ >= kThreadLocalStorageSize) { NOTREACHED(); - return -1; + return false; } // Setup our destructor. - tls_destructors_[slot] = destructor; - return slot; + tls_destructors_[slot_] = destructor; + initialized_ = true; + return true; } -void ThreadLocalStorage::Free(TLSSlot slot) { +void ThreadLocalStorage::Slot::Free() { // At this time, we don't reclaim old indices for TLS slots. // So all we need to do is wipe the destructor. - tls_destructors_[slot] = NULL; + tls_destructors_[slot_] = NULL; + initialized_ = false; } -void* ThreadLocalStorage::Get(TLSSlot slot) { - void **tls_data = static_cast<void**>(TlsGetValue(tls_key_)); +void* ThreadLocalStorage::Slot::Get() const { + void** tls_data = static_cast<void**>(TlsGetValue(tls_key_)); if (!tls_data) - tls_data = Initialize(); - DCHECK(slot >= 0 && slot < kThreadLocalStorageSize); - return tls_data[slot]; + tls_data = ThreadLocalStorage::Initialize(); + DCHECK(slot_ >= 0 && slot_ < kThreadLocalStorageSize); + return tls_data[slot_]; } -void ThreadLocalStorage::Set(TLSSlot slot, void* value) { - void **tls_data = static_cast<void**>(TlsGetValue(tls_key_)); +void ThreadLocalStorage::Slot::Set(void* value) { + void** tls_data = static_cast<void**>(TlsGetValue(tls_key_)); if (!tls_data) - tls_data = Initialize(); - DCHECK(slot >= 0 && slot < kThreadLocalStorageSize); - tls_data[slot] = value; + tls_data = ThreadLocalStorage::Initialize(); + DCHECK(slot_ >= 0 && slot_ < kThreadLocalStorageSize); + tls_data[slot_] = value; } void ThreadLocalStorage::ThreadExit() { - void **tls_data = static_cast<void**>(TlsGetValue(tls_key_)); + void** tls_data = static_cast<void**>(TlsGetValue(tls_key_)); // Maybe we have never initialized TLS for this thread. if (!tls_data) @@ -126,7 +133,7 @@ void ThreadLocalStorage::ThreadExit() { for (int slot = 0; slot < tls_max_; slot++) { if (tls_destructors_[slot] != NULL) { - void *value = tls_data[slot]; + void* value = tls_data[slot]; tls_destructors_[slot](value); } } diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc index b683a87..83a7fbd 100644 --- a/base/tracked_objects.cc +++ b/base/tracked_objects.cc @@ -35,9 +35,9 @@ namespace tracked_objects { -// a TLS index to the TrackRegistry for the current thread. +// A TLS slot to the TrackRegistry for the current thread. // static -TLSSlot ThreadData::tls_index_ = -1; +TLSSlot ThreadData::tls_index_(base::LINKER_INITIALIZED); //------------------------------------------------------------------------------ // Death data tallies durations when a death takes place. @@ -104,15 +104,14 @@ Lock ThreadData::list_lock_; // static ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED; -ThreadData::ThreadData() : message_loop_(MessageLoop::current()) {} +ThreadData::ThreadData() : message_loop_(MessageLoop::current()) {} // static ThreadData* ThreadData::current() { - if (-1 == tls_index_) - return NULL; // not yet initialized. + if (!tls_index_.initialized()) + return NULL; - ThreadData* registry = - static_cast<ThreadData*>(ThreadLocalStorage::Get(tls_index_)); + ThreadData* registry = static_cast<ThreadData*>(tls_index_.Get()); if (!registry) { // We have to create a new registry for ThreadData. bool too_late_to_create = false; @@ -132,7 +131,7 @@ ThreadData* ThreadData::current() { delete registry; registry = NULL; } else { - ThreadLocalStorage::Set(tls_index_, registry); + tls_index_.Set(registry); } } return registry; @@ -344,11 +343,9 @@ bool ThreadData::StartTracking(bool status) { status_ = SHUTDOWN; return true; } - TLSSlot tls_index = ThreadLocalStorage::Alloc(); AutoLock lock(list_lock_); DCHECK(status_ == UNINITIALIZED); - tls_index_ = tls_index; - CHECK(-1 != tls_index_); + CHECK(tls_index_.Initialize(NULL)); status_ = ACTIVE; return true; } @@ -401,9 +398,9 @@ void ThreadData::ShutdownSingleThreadedCleanup() { delete next_thread_data; // Includes all Death Records. } - CHECK(-1 != tls_index_); - ThreadLocalStorage::Free(tls_index_); - tls_index_ = -1; + CHECK(tls_index_.initialized()); + tls_index_.Free(); + DCHECK(!tls_index_.initialized()); status_ = UNINITIALIZED; } |