| 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 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 #endif | 55 #endif |
| 56 | 56 |
| 57 namespace WTF { | 57 namespace WTF { |
| 58 | 58 |
| 59 #if OS(WIN) | 59 #if OS(WIN) |
| 60 // ThreadSpecificThreadExit should be called each time when a thread is detached
. | 60 // ThreadSpecificThreadExit should be called each time when a thread is detached
. |
| 61 // This is done automatically for threads created with WTF::createThread. | 61 // This is done automatically for threads created with WTF::createThread. |
| 62 WTF_EXPORT void ThreadSpecificThreadExit(); | 62 WTF_EXPORT void ThreadSpecificThreadExit(); |
| 63 #endif | 63 #endif |
| 64 | 64 |
| 65 template<typename T> class ThreadSpecific { | 65 template <typename T> |
| 66 WTF_MAKE_NONCOPYABLE(ThreadSpecific); | 66 class ThreadSpecific { |
| 67 public: | 67 WTF_MAKE_NONCOPYABLE(ThreadSpecific); |
| 68 ThreadSpecific(); | |
| 69 bool isSet(); // Useful as a fast check to see if this thread has set this v
alue. | |
| 70 T* operator->(); | |
| 71 operator T*(); | |
| 72 T& operator*(); | |
| 73 | 68 |
| 74 private: | 69 public: |
| 70 ThreadSpecific(); |
| 71 bool isSet(); // Useful as a fast check to see if this thread has set this va
lue. |
| 72 T* operator->(); |
| 73 operator T*(); |
| 74 T& operator*(); |
| 75 |
| 76 private: |
| 75 #if OS(WIN) | 77 #if OS(WIN) |
| 76 WTF_EXPORT friend void ThreadSpecificThreadExit(); | 78 WTF_EXPORT friend void ThreadSpecificThreadExit(); |
| 77 #endif | 79 #endif |
| 78 | 80 |
| 79 // Not implemented. It's technically possible to destroy a thread specific k
ey, but one would need | 81 // Not implemented. It's technically possible to destroy a thread specific key
, but one would need |
| 80 // to make sure that all values have been destroyed already (usually, that a
ll threads that used it | 82 // to make sure that all values have been destroyed already (usually, that all
threads that used it |
| 81 // have exited). It's unlikely that any user of this call will be in that si
tuation - and having | 83 // have exited). It's unlikely that any user of this call will be in that situ
ation - and having |
| 82 // a destructor defined can be confusing, given that it has such strong pre-
requisites to work correctly. | 84 // a destructor defined can be confusing, given that it has such strong pre-re
quisites to work correctly. |
| 83 ~ThreadSpecific(); | 85 ~ThreadSpecific(); |
| 84 | 86 |
| 85 T* get(); | 87 T* get(); |
| 86 void set(T*); | 88 void set(T*); |
| 87 void static destroy(void* ptr); | 89 void static destroy(void* ptr); |
| 88 | 90 |
| 89 struct Data { | 91 struct Data { |
| 90 WTF_MAKE_NONCOPYABLE(Data); | 92 WTF_MAKE_NONCOPYABLE(Data); |
| 91 public: | |
| 92 Data(T* value, ThreadSpecific<T>* owner) : value(value), owner(owner) {} | |
| 93 | 93 |
| 94 T* value; | 94 public: |
| 95 ThreadSpecific<T>* owner; | 95 Data(T* value, ThreadSpecific<T>* owner) |
| 96 : value(value), owner(owner) {} |
| 97 |
| 98 T* value; |
| 99 ThreadSpecific<T>* owner; |
| 96 #if OS(WIN) | 100 #if OS(WIN) |
| 97 void (*destructor)(void*); | 101 void (*destructor)(void*); |
| 98 #endif | 102 #endif |
| 99 }; | 103 }; |
| 100 | 104 |
| 101 #if OS(POSIX) | 105 #if OS(POSIX) |
| 102 pthread_key_t m_key; | 106 pthread_key_t m_key; |
| 103 #elif OS(WIN) | 107 #elif OS(WIN) |
| 104 int m_index; | 108 int m_index; |
| 105 #endif | 109 #endif |
| 106 }; | 110 }; |
| 107 | 111 |
| 108 #if OS(POSIX) | 112 #if OS(POSIX) |
| 109 | 113 |
| 110 typedef pthread_key_t ThreadSpecificKey; | 114 typedef pthread_key_t ThreadSpecificKey; |
| 111 | 115 |
| 112 inline void threadSpecificKeyCreate(ThreadSpecificKey* key, void (*destructor)(v
oid *)) | 116 inline void threadSpecificKeyCreate(ThreadSpecificKey* key, void (*destructor)(v
oid*)) { |
| 113 { | 117 int error = pthread_key_create(key, destructor); |
| 114 int error = pthread_key_create(key, destructor); | 118 if (error) |
| 115 if (error) | 119 CRASH(); |
| 116 CRASH(); | |
| 117 } | 120 } |
| 118 | 121 |
| 119 inline void threadSpecificKeyDelete(ThreadSpecificKey key) | 122 inline void threadSpecificKeyDelete(ThreadSpecificKey key) { |
| 120 { | 123 int error = pthread_key_delete(key); |
| 121 int error = pthread_key_delete(key); | 124 if (error) |
| 122 if (error) | 125 CRASH(); |
| 123 CRASH(); | |
| 124 } | 126 } |
| 125 | 127 |
| 126 inline void threadSpecificSet(ThreadSpecificKey key, void* value) | 128 inline void threadSpecificSet(ThreadSpecificKey key, void* value) { |
| 127 { | 129 pthread_setspecific(key, value); |
| 128 pthread_setspecific(key, value); | |
| 129 } | 130 } |
| 130 | 131 |
| 131 inline void* threadSpecificGet(ThreadSpecificKey key) | 132 inline void* threadSpecificGet(ThreadSpecificKey key) { |
| 132 { | 133 return pthread_getspecific(key); |
| 133 return pthread_getspecific(key); | |
| 134 } | 134 } |
| 135 | 135 |
| 136 template<typename T> | 136 template <typename T> |
| 137 inline ThreadSpecific<T>::ThreadSpecific() | 137 inline ThreadSpecific<T>::ThreadSpecific() { |
| 138 { | 138 int error = pthread_key_create(&m_key, destroy); |
| 139 int error = pthread_key_create(&m_key, destroy); | 139 if (error) |
| 140 if (error) | 140 CRASH(); |
| 141 CRASH(); | |
| 142 } | 141 } |
| 143 | 142 |
| 144 template<typename T> | 143 template <typename T> |
| 145 inline T* ThreadSpecific<T>::get() | 144 inline T* ThreadSpecific<T>::get() { |
| 146 { | 145 Data* data = static_cast<Data*>(pthread_getspecific(m_key)); |
| 147 Data* data = static_cast<Data*>(pthread_getspecific(m_key)); | 146 return data ? data->value : 0; |
| 148 return data ? data->value : 0; | |
| 149 } | 147 } |
| 150 | 148 |
| 151 template<typename T> | 149 template <typename T> |
| 152 inline void ThreadSpecific<T>::set(T* ptr) | 150 inline void ThreadSpecific<T>::set(T* ptr) { |
| 153 { | 151 ASSERT(!get()); |
| 154 ASSERT(!get()); | 152 pthread_setspecific(m_key, new Data(ptr, this)); |
| 155 pthread_setspecific(m_key, new Data(ptr, this)); | |
| 156 } | 153 } |
| 157 | 154 |
| 158 #elif OS(WIN) | 155 #elif OS(WIN) |
| 159 | 156 |
| 160 // TLS_OUT_OF_INDEXES is not defined on WinCE. | 157 // TLS_OUT_OF_INDEXES is not defined on WinCE. |
| 161 #ifndef TLS_OUT_OF_INDEXES | 158 #ifndef TLS_OUT_OF_INDEXES |
| 162 #define TLS_OUT_OF_INDEXES 0xffffffff | 159 #define TLS_OUT_OF_INDEXES 0xffffffff |
| 163 #endif | 160 #endif |
| 164 | 161 |
| 165 // The maximum number of TLS keys that can be created. For simplification, we as
sume that: | 162 // The maximum number of TLS keys that can be created. For simplification, we as
sume that: |
| 166 // 1) Once the instance of ThreadSpecific<> is created, it will not be destructe
d until the program dies. | 163 // 1) Once the instance of ThreadSpecific<> is created, it will not be destructe
d until the program dies. |
| 167 // 2) We do not need to hold many instances of ThreadSpecific<> data. This fixed
number should be far enough. | 164 // 2) We do not need to hold many instances of ThreadSpecific<> data. This fixed
number should be far enough. |
| 168 const int kMaxTlsKeySize = 256; | 165 const int kMaxTlsKeySize = 256; |
| 169 | 166 |
| 170 WTF_EXPORT long& tlsKeyCount(); | 167 WTF_EXPORT long& tlsKeyCount(); |
| 171 WTF_EXPORT DWORD* tlsKeys(); | 168 WTF_EXPORT DWORD* tlsKeys(); |
| 172 | 169 |
| 173 class PlatformThreadSpecificKey; | 170 class PlatformThreadSpecificKey; |
| 174 typedef PlatformThreadSpecificKey* ThreadSpecificKey; | 171 typedef PlatformThreadSpecificKey* ThreadSpecificKey; |
| 175 | 172 |
| 176 WTF_EXPORT void threadSpecificKeyCreate(ThreadSpecificKey*, void (*)(void *)); | 173 WTF_EXPORT void threadSpecificKeyCreate(ThreadSpecificKey*, void (*)(void*)); |
| 177 WTF_EXPORT void threadSpecificKeyDelete(ThreadSpecificKey); | 174 WTF_EXPORT void threadSpecificKeyDelete(ThreadSpecificKey); |
| 178 WTF_EXPORT void threadSpecificSet(ThreadSpecificKey, void*); | 175 WTF_EXPORT void threadSpecificSet(ThreadSpecificKey, void*); |
| 179 WTF_EXPORT void* threadSpecificGet(ThreadSpecificKey); | 176 WTF_EXPORT void* threadSpecificGet(ThreadSpecificKey); |
| 180 | 177 |
| 181 template<typename T> | 178 template <typename T> |
| 182 inline ThreadSpecific<T>::ThreadSpecific() | 179 inline ThreadSpecific<T>::ThreadSpecific() |
| 183 : m_index(-1) | 180 : m_index(-1) { |
| 184 { | 181 DWORD tlsKey = TlsAlloc(); |
| 185 DWORD tlsKey = TlsAlloc(); | 182 if (tlsKey == TLS_OUT_OF_INDEXES) |
| 186 if (tlsKey == TLS_OUT_OF_INDEXES) | 183 CRASH(); |
| 187 CRASH(); | |
| 188 | 184 |
| 189 m_index = InterlockedIncrement(&tlsKeyCount()) - 1; | 185 m_index = InterlockedIncrement(&tlsKeyCount()) - 1; |
| 190 if (m_index >= kMaxTlsKeySize) | 186 if (m_index >= kMaxTlsKeySize) |
| 191 CRASH(); | 187 CRASH(); |
| 192 tlsKeys()[m_index] = tlsKey; | 188 tlsKeys()[m_index] = tlsKey; |
| 193 } | 189 } |
| 194 | 190 |
| 195 template<typename T> | 191 template <typename T> |
| 196 inline ThreadSpecific<T>::~ThreadSpecific() | 192 inline ThreadSpecific<T>::~ThreadSpecific() { |
| 197 { | 193 // Does not invoke destructor functions. They will be called from ThreadSpecif
icThreadExit when the thread is detached. |
| 198 // Does not invoke destructor functions. They will be called from ThreadSpec
ificThreadExit when the thread is detached. | 194 TlsFree(tlsKeys()[m_index]); |
| 199 TlsFree(tlsKeys()[m_index]); | |
| 200 } | 195 } |
| 201 | 196 |
| 202 template<typename T> | 197 template <typename T> |
| 203 inline T* ThreadSpecific<T>::get() | 198 inline T* ThreadSpecific<T>::get() { |
| 204 { | 199 Data* data = static_cast<Data*>(TlsGetValue(tlsKeys()[m_index])); |
| 205 Data* data = static_cast<Data*>(TlsGetValue(tlsKeys()[m_index])); | 200 return data ? data->value : 0; |
| 206 return data ? data->value : 0; | |
| 207 } | 201 } |
| 208 | 202 |
| 209 template<typename T> | 203 template <typename T> |
| 210 inline void ThreadSpecific<T>::set(T* ptr) | 204 inline void ThreadSpecific<T>::set(T* ptr) { |
| 211 { | 205 ASSERT(!get()); |
| 212 ASSERT(!get()); | 206 Data* data = new Data(ptr, this); |
| 213 Data* data = new Data(ptr, this); | 207 data->destructor = &ThreadSpecific<T>::destroy; |
| 214 data->destructor = &ThreadSpecific<T>::destroy; | 208 TlsSetValue(tlsKeys()[m_index], data); |
| 215 TlsSetValue(tlsKeys()[m_index], data); | |
| 216 } | 209 } |
| 217 | 210 |
| 218 #else | 211 #else |
| 219 #error ThreadSpecific is not implemented for this platform. | 212 #error ThreadSpecific is not implemented for this platform. |
| 220 #endif | 213 #endif |
| 221 | 214 |
| 222 template<typename T> | 215 template <typename T> |
| 223 inline void ThreadSpecific<T>::destroy(void* ptr) | 216 inline void ThreadSpecific<T>::destroy(void* ptr) { |
| 224 { | 217 if (isShutdown()) |
| 225 if (isShutdown()) | 218 return; |
| 226 return; | |
| 227 | 219 |
| 228 Data* data = static_cast<Data*>(ptr); | 220 Data* data = static_cast<Data*>(ptr); |
| 229 | 221 |
| 230 #if OS(POSIX) | 222 #if OS(POSIX) |
| 231 // We want get() to keep working while data destructor works, because it can
be called indirectly by the destructor. | 223 // We want get() to keep working while data destructor works, because it can b
e called indirectly by the destructor. |
| 232 // Some pthreads implementations zero out the pointer before calling destroy
(), so we temporarily reset it. | 224 // Some pthreads implementations zero out the pointer before calling destroy()
, so we temporarily reset it. |
| 233 pthread_setspecific(data->owner->m_key, ptr); | 225 pthread_setspecific(data->owner->m_key, ptr); |
| 234 #endif | 226 #endif |
| 235 | 227 |
| 236 data->value->~T(); | 228 data->value->~T(); |
| 237 Partitions::fastFree(data->value); | 229 Partitions::fastFree(data->value); |
| 238 | 230 |
| 239 #if OS(POSIX) | 231 #if OS(POSIX) |
| 240 pthread_setspecific(data->owner->m_key, 0); | 232 pthread_setspecific(data->owner->m_key, 0); |
| 241 #elif OS(WIN) | 233 #elif OS(WIN) |
| 242 TlsSetValue(tlsKeys()[data->owner->m_index], 0); | 234 TlsSetValue(tlsKeys()[data->owner->m_index], 0); |
| 243 #else | 235 #else |
| 244 #error ThreadSpecific is not implemented for this platform. | 236 #error ThreadSpecific is not implemented for this platform. |
| 245 #endif | 237 #endif |
| 246 | 238 |
| 247 delete data; | 239 delete data; |
| 248 } | 240 } |
| 249 | 241 |
| 250 template<typename T> | 242 template <typename T> |
| 251 inline bool ThreadSpecific<T>::isSet() | 243 inline bool ThreadSpecific<T>::isSet() { |
| 252 { | 244 return !!get(); |
| 253 return !!get(); | |
| 254 } | 245 } |
| 255 | 246 |
| 256 template<typename T> | 247 template <typename T> |
| 257 inline ThreadSpecific<T>::operator T*() | 248 inline ThreadSpecific<T>::operator T*() { |
| 258 { | 249 T* ptr = static_cast<T*>(get()); |
| 259 T* ptr = static_cast<T*>(get()); | 250 if (!ptr) { |
| 260 if (!ptr) { | 251 // Set up thread-specific value's memory pointer before invoking constructor
, in case any function it calls |
| 261 // Set up thread-specific value's memory pointer before invoking constru
ctor, in case any function it calls | 252 // needs to access the value, to avoid recursion. |
| 262 // needs to access the value, to avoid recursion. | 253 ptr = static_cast<T*>(Partitions::fastZeroedMalloc(sizeof(T))); |
| 263 ptr = static_cast<T*>(Partitions::fastZeroedMalloc(sizeof(T))); | 254 set(ptr); |
| 264 set(ptr); | 255 new (NotNull, ptr) T; |
| 265 new (NotNull, ptr) T; | 256 } |
| 266 } | 257 return ptr; |
| 267 return ptr; | |
| 268 } | 258 } |
| 269 | 259 |
| 270 template<typename T> | 260 template <typename T> |
| 271 inline T* ThreadSpecific<T>::operator->() | 261 inline T* ThreadSpecific<T>::operator->() { |
| 272 { | 262 return operator T*(); |
| 273 return operator T*(); | |
| 274 } | 263 } |
| 275 | 264 |
| 276 template<typename T> | 265 template <typename T> |
| 277 inline T& ThreadSpecific<T>::operator*() | 266 inline T& ThreadSpecific<T>::operator*() { |
| 278 { | 267 return *operator T*(); |
| 279 return *operator T*(); | |
| 280 } | 268 } |
| 281 | 269 |
| 282 } // namespace WTF | 270 } // namespace WTF |
| 283 | 271 |
| 284 using WTF::ThreadSpecific; | 272 using WTF::ThreadSpecific; |
| 285 | 273 |
| 286 #endif // WTF_ThreadSpecific_h | 274 #endif // WTF_ThreadSpecific_h |
| OLD | NEW |