Chromium Code Reviews| Index: third_party/WebKit/Source/wtf/ThreadSpecific.h |
| diff --git a/third_party/WebKit/Source/wtf/ThreadSpecific.h b/third_party/WebKit/Source/wtf/ThreadSpecific.h |
| index 2e82293b59ea0f9fb2b5c81bc52b279ea5513cb1..36ff6568f2cdce8ceb5d4c748005dc8e2219efd2 100644 |
| --- a/third_party/WebKit/Source/wtf/ThreadSpecific.h |
| +++ b/third_party/WebKit/Source/wtf/ThreadSpecific.h |
| @@ -42,244 +42,58 @@ |
| #ifndef WTF_ThreadSpecific_h |
| #define WTF_ThreadSpecific_h |
| +#include "base/threading/thread_local_storage.h" |
| #include "wtf/Allocator.h" |
| #include "wtf/Noncopyable.h" |
| #include "wtf/Partitions.h" |
| -#include "wtf/StdLibExtras.h" |
| #include "wtf/WTF.h" |
| -#include "wtf/WTFExport.h" |
| - |
| -#if OS(POSIX) |
| -#include <pthread.h> |
| -#elif OS(WIN) |
| -#include <windows.h> |
| -#endif |
| namespace WTF { |
| -#if OS(WIN) |
| -// ThreadSpecificThreadExit should be called each time when a thread is detached. |
| -// This is done automatically for threads created with WTF::createThread. |
| -WTF_EXPORT void ThreadSpecificThreadExit(); |
| -#endif |
| - |
| -template<typename T> class ThreadSpecific { |
| +template<typename T> |
| +class ThreadSpecific { |
| USING_FAST_MALLOC(ThreadSpecific); |
| WTF_MAKE_NONCOPYABLE(ThreadSpecific); |
| public: |
| - ThreadSpecific(); |
| - bool isSet(); // Useful as a fast check to see if this thread has set this value. |
| - T* operator->(); |
| - operator T*(); |
| - T& operator*(); |
| + ThreadSpecific() |
| + : m_slot(&destory) |
| + { } |
| -private: |
| -#if OS(WIN) |
| - WTF_EXPORT friend void ThreadSpecificThreadExit(); |
| -#endif |
| + operator T*() { return get(); } |
| + T* operator->() { return get(); } |
| + T& operator*() { return *get(); } |
| +private: |
| // Not implemented. It's technically possible to destroy a thread specific key, but one would need |
| // to make sure that all values have been destroyed already (usually, that all threads that used it |
| // have exited). It's unlikely that any user of this call will be in that situation - and having |
| // a destructor defined can be confusing, given that it has such strong pre-requisites to work correctly. |
| ~ThreadSpecific(); |
| - T* get(); |
| - void set(T*); |
| - void static destroy(void* ptr); |
| - |
| - struct Data { |
| - WTF_MAKE_NONCOPYABLE(Data); |
| - public: |
| - Data(T* value, ThreadSpecific<T>* owner) : value(value), owner(owner) {} |
| - |
| - T* value; |
| - ThreadSpecific<T>* owner; |
| -#if OS(WIN) |
| - void (*destructor)(void*); |
| -#endif |
| - }; |
| - |
| -#if OS(POSIX) |
| - pthread_key_t m_key; |
| -#elif OS(WIN) |
| - int m_index; |
| -#endif |
| -}; |
| - |
| -#if OS(POSIX) |
| - |
| -typedef pthread_key_t ThreadSpecificKey; |
| - |
| -inline void threadSpecificKeyCreate(ThreadSpecificKey* key, void (*destructor)(void *)) |
| -{ |
| - int error = pthread_key_create(key, destructor); |
| - if (error) |
| - CRASH(); |
| -} |
| - |
| -inline void threadSpecificKeyDelete(ThreadSpecificKey key) |
| -{ |
| - int error = pthread_key_delete(key); |
| - if (error) |
| - CRASH(); |
| -} |
| - |
| -inline void threadSpecificSet(ThreadSpecificKey key, void* value) |
| -{ |
| - pthread_setspecific(key, value); |
| -} |
| - |
| -inline void* threadSpecificGet(ThreadSpecificKey key) |
| -{ |
| - return pthread_getspecific(key); |
| -} |
| - |
| -template<typename T> |
| -inline ThreadSpecific<T>::ThreadSpecific() |
| -{ |
| - int error = pthread_key_create(&m_key, destroy); |
| - if (error) |
| - CRASH(); |
| -} |
| - |
| -template<typename T> |
| -inline T* ThreadSpecific<T>::get() |
| -{ |
| - Data* data = static_cast<Data*>(pthread_getspecific(m_key)); |
| - return data ? data->value : 0; |
| -} |
| - |
| -template<typename T> |
| -inline void ThreadSpecific<T>::set(T* ptr) |
| -{ |
| - ASSERT(!get()); |
| - pthread_setspecific(m_key, new Data(ptr, this)); |
| -} |
| - |
| -#elif OS(WIN) |
| - |
| -// TLS_OUT_OF_INDEXES is not defined on WinCE. |
| -#ifndef TLS_OUT_OF_INDEXES |
| -#define TLS_OUT_OF_INDEXES 0xffffffff |
| -#endif |
| - |
| -// The maximum number of TLS keys that can be created. For simplification, we assume that: |
| -// 1) Once the instance of ThreadSpecific<> is created, it will not be destructed until the program dies. |
| -// 2) We do not need to hold many instances of ThreadSpecific<> data. This fixed number should be far enough. |
| -const int kMaxTlsKeySize = 256; |
| - |
| -WTF_EXPORT long& tlsKeyCount(); |
| -WTF_EXPORT DWORD* tlsKeys(); |
| - |
| -class PlatformThreadSpecificKey; |
| -typedef PlatformThreadSpecificKey* ThreadSpecificKey; |
| - |
| -WTF_EXPORT void threadSpecificKeyCreate(ThreadSpecificKey*, void (*)(void *)); |
| -WTF_EXPORT void threadSpecificKeyDelete(ThreadSpecificKey); |
| -WTF_EXPORT void threadSpecificSet(ThreadSpecificKey, void*); |
| -WTF_EXPORT void* threadSpecificGet(ThreadSpecificKey); |
| - |
| -template<typename T> |
| -inline ThreadSpecific<T>::ThreadSpecific() |
| - : m_index(-1) |
| -{ |
| - DWORD tlsKey = TlsAlloc(); |
| - if (tlsKey == TLS_OUT_OF_INDEXES) |
| - CRASH(); |
| - |
| - m_index = InterlockedIncrement(&tlsKeyCount()) - 1; |
| - if (m_index >= kMaxTlsKeySize) |
| - CRASH(); |
| - tlsKeys()[m_index] = tlsKey; |
| -} |
| - |
| -template<typename T> |
| -inline ThreadSpecific<T>::~ThreadSpecific() |
| -{ |
| - // Does not invoke destructor functions. They will be called from ThreadSpecificThreadExit when the thread is detached. |
| - TlsFree(tlsKeys()[m_index]); |
| -} |
| - |
| -template<typename T> |
| -inline T* ThreadSpecific<T>::get() |
| -{ |
| - Data* data = static_cast<Data*>(TlsGetValue(tlsKeys()[m_index])); |
| - return data ? data->value : 0; |
| -} |
| - |
| -template<typename T> |
| -inline void ThreadSpecific<T>::set(T* ptr) |
| -{ |
| - ASSERT(!get()); |
| - Data* data = new Data(ptr, this); |
| - data->destructor = &ThreadSpecific<T>::destroy; |
| - TlsSetValue(tlsKeys()[m_index], data); |
| -} |
| - |
| -#else |
| -#error ThreadSpecific is not implemented for this platform. |
| -#endif |
| - |
| -template<typename T> |
| -inline void ThreadSpecific<T>::destroy(void* ptr) |
| -{ |
| - if (isShutdown()) |
| - return; |
| - |
| - Data* data = static_cast<Data*>(ptr); |
| - |
| -#if OS(POSIX) |
| - // We want get() to keep working while data destructor works, because it can be called indirectly by the destructor. |
| - // Some pthreads implementations zero out the pointer before calling destroy(), so we temporarily reset it. |
| - pthread_setspecific(data->owner->m_key, ptr); |
| -#endif |
| - |
| - data->value->~T(); |
| - Partitions::fastFree(data->value); |
| - |
| -#if OS(POSIX) |
| - pthread_setspecific(data->owner->m_key, 0); |
| -#elif OS(WIN) |
| - TlsSetValue(tlsKeys()[data->owner->m_index], 0); |
| -#else |
| -#error ThreadSpecific is not implemented for this platform. |
| -#endif |
| - |
| - delete data; |
| -} |
| - |
| -template<typename T> |
| -inline bool ThreadSpecific<T>::isSet() |
| -{ |
| - return !!get(); |
| -} |
| - |
| -template<typename T> |
| -inline ThreadSpecific<T>::operator T*() |
| -{ |
| - T* ptr = static_cast<T*>(get()); |
| - if (!ptr) { |
| - // Set up thread-specific value's memory pointer before invoking constructor, in case any function it calls |
| - // needs to access the value, to avoid recursion. |
| - ptr = static_cast<T*>(Partitions::fastZeroedMalloc(sizeof(T), WTF_HEAP_PROFILER_TYPE_NAME(T))); |
| - set(ptr); |
| - new (NotNull, ptr) T; |
| + T* get() |
| + { |
| + T* ptr = static_cast<T*>(m_slot.Get()); |
| + if (!ptr) { |
| + // Set up thread-specific value's memory pointer before invoking constructor, in case any function it calls |
| + // needs to access the value, to avoid recursion. |
| + ptr = static_cast<T*>(Partitions::fastZeroedMalloc(sizeof(T), WTF_HEAP_PROFILER_TYPE_NAME(T))); |
| + m_slot.Set(ptr); |
| + new (NotNull, ptr) T; |
| + } |
| + return ptr; |
| } |
| - return ptr; |
| -} |
| -template<typename T> |
| -inline T* ThreadSpecific<T>::operator->() |
| -{ |
| - return operator T*(); |
| -} |
| + static void destory(void* value) |
| + { |
| + if (isShutdown()) |
|
haraken
2016/04/01 12:28:35
I'm not sure if this check is needed though.
|
| + return; |
| + T* ptr = static_cast<T*>(value); |
| + ptr->~T(); |
| + Partitions::fastFree(ptr); |
| + } |
| -template<typename T> |
| -inline T& ThreadSpecific<T>::operator*() |
| -{ |
| - return *operator T*(); |
| -} |
| + base::ThreadLocalStorage::Slot m_slot; |
| +}; |
| } // namespace WTF |