Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2008 Apple Inc. All rights reserved. |
| 3 * Copyright (C) 2009 Jian Li <jianli@chromium.org> | 3 * Copyright (C) 2009 Jian Li <jianli@chromium.org> |
| 4 * Copyright (C) 2012 Patrick Gansterer <paroga@paroga.com> | 4 * Copyright (C) 2012 Patrick Gansterer <paroga@paroga.com> |
| 5 * | 5 * |
| 6 * Redistribution and use in source and binary forms, with or without | 6 * Redistribution and use in source and binary forms, with or without |
| 7 * modification, are permitted provided that the following conditions | 7 * modification, are permitted provided that the following conditions |
| 8 * are met: | 8 * are met: |
| 9 * | 9 * |
| 10 * 1. Redistributions of source code must retain the above copyright | 10 * 1. Redistributions of source code must retain the above copyright |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 35 * repeatedly if there is still non-NULL value associated with the function. | 35 * repeatedly if there is still non-NULL value associated with the function. |
| 36 * @ In Windows native implementation, the destructor function will be called | 36 * @ In Windows native implementation, the destructor function will be called |
| 37 * only once. | 37 * only once. |
| 38 * This semantic discrepancy does not impose any problem because nowhere in | 38 * This semantic discrepancy does not impose any problem because nowhere in |
| 39 * WebKit the repeated call bahavior is utilized. | 39 * WebKit the repeated call bahavior is utilized. |
| 40 */ | 40 */ |
| 41 | 41 |
| 42 #ifndef WTF_ThreadSpecific_h | 42 #ifndef WTF_ThreadSpecific_h |
| 43 #define WTF_ThreadSpecific_h | 43 #define WTF_ThreadSpecific_h |
| 44 | 44 |
| 45 #include "base/threading/thread_local_storage.h" | |
| 45 #include "wtf/Allocator.h" | 46 #include "wtf/Allocator.h" |
| 46 #include "wtf/Noncopyable.h" | 47 #include "wtf/Noncopyable.h" |
| 47 #include "wtf/Partitions.h" | 48 #include "wtf/Partitions.h" |
| 48 #include "wtf/StdLibExtras.h" | |
| 49 #include "wtf/WTF.h" | 49 #include "wtf/WTF.h" |
| 50 #include "wtf/WTFExport.h" | |
| 51 | |
| 52 #if OS(POSIX) | |
| 53 #include <pthread.h> | |
| 54 #elif OS(WIN) | |
| 55 #include <windows.h> | |
| 56 #endif | |
| 57 | 50 |
| 58 namespace WTF { | 51 namespace WTF { |
| 59 | 52 |
| 60 #if OS(WIN) | 53 template<typename T> |
| 61 // ThreadSpecificThreadExit should be called each time when a thread is detached . | 54 class ThreadSpecific { |
| 62 // This is done automatically for threads created with WTF::createThread. | |
| 63 WTF_EXPORT void ThreadSpecificThreadExit(); | |
| 64 #endif | |
| 65 | |
| 66 template<typename T> class ThreadSpecific { | |
| 67 USING_FAST_MALLOC(ThreadSpecific); | 55 USING_FAST_MALLOC(ThreadSpecific); |
| 68 WTF_MAKE_NONCOPYABLE(ThreadSpecific); | 56 WTF_MAKE_NONCOPYABLE(ThreadSpecific); |
| 69 public: | 57 public: |
| 70 ThreadSpecific(); | 58 ThreadSpecific() |
| 71 bool isSet(); // Useful as a fast check to see if this thread has set this v alue. | 59 : m_slot(&destory) |
| 72 T* operator->(); | 60 { } |
| 73 operator T*(); | 61 |
| 74 T& operator*(); | 62 operator T*() { return get(); } |
| 63 T* operator->() { return get(); } | |
| 64 T& operator*() { return *get(); } | |
| 75 | 65 |
| 76 private: | 66 private: |
| 77 #if OS(WIN) | |
| 78 WTF_EXPORT friend void ThreadSpecificThreadExit(); | |
| 79 #endif | |
| 80 | |
| 81 // Not implemented. It's technically possible to destroy a thread specific k ey, but one would need | 67 // Not implemented. It's technically possible to destroy a thread specific k ey, but one would need |
| 82 // to make sure that all values have been destroyed already (usually, that a ll threads that used it | 68 // to make sure that all values have been destroyed already (usually, that a ll threads that used it |
| 83 // have exited). It's unlikely that any user of this call will be in that si tuation - and having | 69 // have exited). It's unlikely that any user of this call will be in that si tuation - and having |
| 84 // a destructor defined can be confusing, given that it has such strong pre- requisites to work correctly. | 70 // a destructor defined can be confusing, given that it has such strong pre- requisites to work correctly. |
| 85 ~ThreadSpecific(); | 71 ~ThreadSpecific(); |
| 86 | 72 |
| 87 T* get(); | 73 T* get() |
| 88 void set(T*); | 74 { |
| 89 void static destroy(void* ptr); | 75 T* ptr = static_cast<T*>(m_slot.Get()); |
| 76 if (!ptr) { | |
| 77 // Set up thread-specific value's memory pointer before invoking con structor, in case any function it calls | |
| 78 // needs to access the value, to avoid recursion. | |
| 79 ptr = static_cast<T*>(Partitions::fastZeroedMalloc(sizeof(T), WTF_HE AP_PROFILER_TYPE_NAME(T))); | |
| 80 m_slot.Set(ptr); | |
| 81 new (NotNull, ptr) T; | |
| 82 } | |
| 83 return ptr; | |
| 84 } | |
| 90 | 85 |
| 91 struct Data { | 86 static void destory(void* value) |
| 92 WTF_MAKE_NONCOPYABLE(Data); | 87 { |
| 93 public: | 88 if (isShutdown()) |
|
haraken
2016/04/01 12:28:35
I'm not sure if this check is needed though.
| |
| 94 Data(T* value, ThreadSpecific<T>* owner) : value(value), owner(owner) {} | 89 return; |
| 90 T* ptr = static_cast<T*>(value); | |
| 91 ptr->~T(); | |
| 92 Partitions::fastFree(ptr); | |
| 93 } | |
| 95 | 94 |
| 96 T* value; | 95 base::ThreadLocalStorage::Slot m_slot; |
| 97 ThreadSpecific<T>* owner; | |
| 98 #if OS(WIN) | |
| 99 void (*destructor)(void*); | |
| 100 #endif | |
| 101 }; | |
| 102 | |
| 103 #if OS(POSIX) | |
| 104 pthread_key_t m_key; | |
| 105 #elif OS(WIN) | |
| 106 int m_index; | |
| 107 #endif | |
| 108 }; | 96 }; |
| 109 | 97 |
| 110 #if OS(POSIX) | |
| 111 | |
| 112 typedef pthread_key_t ThreadSpecificKey; | |
| 113 | |
| 114 inline void threadSpecificKeyCreate(ThreadSpecificKey* key, void (*destructor)(v oid *)) | |
| 115 { | |
| 116 int error = pthread_key_create(key, destructor); | |
| 117 if (error) | |
| 118 CRASH(); | |
| 119 } | |
| 120 | |
| 121 inline void threadSpecificKeyDelete(ThreadSpecificKey key) | |
| 122 { | |
| 123 int error = pthread_key_delete(key); | |
| 124 if (error) | |
| 125 CRASH(); | |
| 126 } | |
| 127 | |
| 128 inline void threadSpecificSet(ThreadSpecificKey key, void* value) | |
| 129 { | |
| 130 pthread_setspecific(key, value); | |
| 131 } | |
| 132 | |
| 133 inline void* threadSpecificGet(ThreadSpecificKey key) | |
| 134 { | |
| 135 return pthread_getspecific(key); | |
| 136 } | |
| 137 | |
| 138 template<typename T> | |
| 139 inline ThreadSpecific<T>::ThreadSpecific() | |
| 140 { | |
| 141 int error = pthread_key_create(&m_key, destroy); | |
| 142 if (error) | |
| 143 CRASH(); | |
| 144 } | |
| 145 | |
| 146 template<typename T> | |
| 147 inline T* ThreadSpecific<T>::get() | |
| 148 { | |
| 149 Data* data = static_cast<Data*>(pthread_getspecific(m_key)); | |
| 150 return data ? data->value : 0; | |
| 151 } | |
| 152 | |
| 153 template<typename T> | |
| 154 inline void ThreadSpecific<T>::set(T* ptr) | |
| 155 { | |
| 156 ASSERT(!get()); | |
| 157 pthread_setspecific(m_key, new Data(ptr, this)); | |
| 158 } | |
| 159 | |
| 160 #elif OS(WIN) | |
| 161 | |
| 162 // TLS_OUT_OF_INDEXES is not defined on WinCE. | |
| 163 #ifndef TLS_OUT_OF_INDEXES | |
| 164 #define TLS_OUT_OF_INDEXES 0xffffffff | |
| 165 #endif | |
| 166 | |
| 167 // The maximum number of TLS keys that can be created. For simplification, we as sume that: | |
| 168 // 1) Once the instance of ThreadSpecific<> is created, it will not be destructe d until the program dies. | |
| 169 // 2) We do not need to hold many instances of ThreadSpecific<> data. This fixed number should be far enough. | |
| 170 const int kMaxTlsKeySize = 256; | |
| 171 | |
| 172 WTF_EXPORT long& tlsKeyCount(); | |
| 173 WTF_EXPORT DWORD* tlsKeys(); | |
| 174 | |
| 175 class PlatformThreadSpecificKey; | |
| 176 typedef PlatformThreadSpecificKey* ThreadSpecificKey; | |
| 177 | |
| 178 WTF_EXPORT void threadSpecificKeyCreate(ThreadSpecificKey*, void (*)(void *)); | |
| 179 WTF_EXPORT void threadSpecificKeyDelete(ThreadSpecificKey); | |
| 180 WTF_EXPORT void threadSpecificSet(ThreadSpecificKey, void*); | |
| 181 WTF_EXPORT void* threadSpecificGet(ThreadSpecificKey); | |
| 182 | |
| 183 template<typename T> | |
| 184 inline ThreadSpecific<T>::ThreadSpecific() | |
| 185 : m_index(-1) | |
| 186 { | |
| 187 DWORD tlsKey = TlsAlloc(); | |
| 188 if (tlsKey == TLS_OUT_OF_INDEXES) | |
| 189 CRASH(); | |
| 190 | |
| 191 m_index = InterlockedIncrement(&tlsKeyCount()) - 1; | |
| 192 if (m_index >= kMaxTlsKeySize) | |
| 193 CRASH(); | |
| 194 tlsKeys()[m_index] = tlsKey; | |
| 195 } | |
| 196 | |
| 197 template<typename T> | |
| 198 inline ThreadSpecific<T>::~ThreadSpecific() | |
| 199 { | |
| 200 // Does not invoke destructor functions. They will be called from ThreadSpec ificThreadExit when the thread is detached. | |
| 201 TlsFree(tlsKeys()[m_index]); | |
| 202 } | |
| 203 | |
| 204 template<typename T> | |
| 205 inline T* ThreadSpecific<T>::get() | |
| 206 { | |
| 207 Data* data = static_cast<Data*>(TlsGetValue(tlsKeys()[m_index])); | |
| 208 return data ? data->value : 0; | |
| 209 } | |
| 210 | |
| 211 template<typename T> | |
| 212 inline void ThreadSpecific<T>::set(T* ptr) | |
| 213 { | |
| 214 ASSERT(!get()); | |
| 215 Data* data = new Data(ptr, this); | |
| 216 data->destructor = &ThreadSpecific<T>::destroy; | |
| 217 TlsSetValue(tlsKeys()[m_index], data); | |
| 218 } | |
| 219 | |
| 220 #else | |
| 221 #error ThreadSpecific is not implemented for this platform. | |
| 222 #endif | |
| 223 | |
| 224 template<typename T> | |
| 225 inline void ThreadSpecific<T>::destroy(void* ptr) | |
| 226 { | |
| 227 if (isShutdown()) | |
| 228 return; | |
| 229 | |
| 230 Data* data = static_cast<Data*>(ptr); | |
| 231 | |
| 232 #if OS(POSIX) | |
| 233 // We want get() to keep working while data destructor works, because it can be called indirectly by the destructor. | |
| 234 // Some pthreads implementations zero out the pointer before calling destroy (), so we temporarily reset it. | |
| 235 pthread_setspecific(data->owner->m_key, ptr); | |
| 236 #endif | |
| 237 | |
| 238 data->value->~T(); | |
| 239 Partitions::fastFree(data->value); | |
| 240 | |
| 241 #if OS(POSIX) | |
| 242 pthread_setspecific(data->owner->m_key, 0); | |
| 243 #elif OS(WIN) | |
| 244 TlsSetValue(tlsKeys()[data->owner->m_index], 0); | |
| 245 #else | |
| 246 #error ThreadSpecific is not implemented for this platform. | |
| 247 #endif | |
| 248 | |
| 249 delete data; | |
| 250 } | |
| 251 | |
| 252 template<typename T> | |
| 253 inline bool ThreadSpecific<T>::isSet() | |
| 254 { | |
| 255 return !!get(); | |
| 256 } | |
| 257 | |
| 258 template<typename T> | |
| 259 inline ThreadSpecific<T>::operator T*() | |
| 260 { | |
| 261 T* ptr = static_cast<T*>(get()); | |
| 262 if (!ptr) { | |
| 263 // Set up thread-specific value's memory pointer before invoking constru ctor, in case any function it calls | |
| 264 // needs to access the value, to avoid recursion. | |
| 265 ptr = static_cast<T*>(Partitions::fastZeroedMalloc(sizeof(T), WTF_HEAP_P ROFILER_TYPE_NAME(T))); | |
| 266 set(ptr); | |
| 267 new (NotNull, ptr) T; | |
| 268 } | |
| 269 return ptr; | |
| 270 } | |
| 271 | |
| 272 template<typename T> | |
| 273 inline T* ThreadSpecific<T>::operator->() | |
| 274 { | |
| 275 return operator T*(); | |
| 276 } | |
| 277 | |
| 278 template<typename T> | |
| 279 inline T& ThreadSpecific<T>::operator*() | |
| 280 { | |
| 281 return *operator T*(); | |
| 282 } | |
| 283 | |
| 284 } // namespace WTF | 98 } // namespace WTF |
| 285 | 99 |
| 286 using WTF::ThreadSpecific; | 100 using WTF::ThreadSpecific; |
| 287 | 101 |
| 288 #endif // WTF_ThreadSpecific_h | 102 #endif // WTF_ThreadSpecific_h |
| OLD | NEW |