2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_THREAD_LOCAL_H_
18 #define incl_HPHP_THREAD_LOCAL_H_
22 #include <type_traits>
24 #include <folly/String.h>
26 #include "hphp/util/exception.h"
27 #include "hphp/util/type-scan.h"
31 // return the location of the current thread's tdata section
32 std::pair
<void*,size_t> getCppTdata();
35 extern "C" int _tls_index
;
38 inline uintptr_t tlsBase() {
40 #if defined(__x86_64__)
41 asm ("movq %%fs:0, %0" : "=r" (retval
));
42 #elif defined(__AARCH64EL__)
43 // mrs == "move register <-- system"
44 // tpidr_el0 == "thread process id register for exception level 0"
45 asm ("mrs %0, tpidr_el0" : "=r" (retval
));
46 #elif defined (__powerpc64__)
47 asm ("xor %0,%0,%0\n\t"
51 retval
= (uintptr_t)__readgsqword(88);
52 retval
= *(uintptr_t*)(retval
+ (_tls_index
* 8));
54 # error How do you access thread-local storage on this machine?
59 ///////////////////////////////////////////////////////////////////////////////
60 // gcc >= 4.3.0 supports the '__thread' keyword for thread locals
62 // Clang seems to have added this feature, or at the very least it is ignoring
63 // __thread keyword and compiling anyway
65 // On OSX, gcc does emulate TLS but in a manner that invalidates assumptions
66 // we have made about __thread and makes accessing thread-local variables in a
67 // JIT-friendly fashion difficult (as the compiler is doing a lot of magic that
68 // is not contractual or documented that we would need to duplicate in emitted
69 // code) so for now we're not going to use it. One possibility if we really
70 // want to do this is to generate functions that access variables of interest
71 // in ThreadLocal* (all of them are NoCheck right now) and use the bytes of
72 // gcc's compiled functions to find the values we would need to pass to
73 // __emutls_get_address.
75 // icc 13.0.0 appears to support it as well but we end up with
76 // assembler warnings of unknown importance about incorrect section
79 // __thread on cygwin and mingw uses pthreads emulation not native tls so
80 // the emulation for thread local must be used as well
82 // So we use __thread on gcc, icc and clang, and OSX, falling back to
83 // emulation on unsupported platforms. Use the THREAD_LOCAL() macro to
84 // hide the decl details.
86 // See thread-local-emulate.h for the emulated versions; they're in a
87 // separate header to avoid confusion; this is a long header file and it's
88 // easy to lose track of which version you're looking at.
90 #if !defined(NO_TLS) && \
91 ((__llvm__ && __clang__) || \
92 __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 3) || \
93 __INTEL_COMPILER || defined(_MSC_VER))
94 #define USE_GCC_FAST_TLS
97 ///////////////////////////////////////////////////////////////////////////////
100 inline void ThreadLocalCheckReturn(int ret
, const char *funcName
) {
102 // This is used from global constructors so the safest thing to do is just
103 // print to stderr and exit().
104 fprintf(stderr
, "%s returned %d: %s", funcName
, ret
,
105 folly::errnoStr(ret
).c_str());
110 inline void ThreadLocalCreateKey(pthread_key_t
*key
, void (*del
)(void*)) {
111 int ret
= pthread_key_create(key
, del
);
112 ThreadLocalCheckReturn(ret
, "pthread_key_create");
115 inline void ThreadLocalSetValue(pthread_key_t key
, const void* value
) {
116 int ret
= pthread_setspecific(key
, value
);
117 ThreadLocalCheckReturn(ret
, "pthread_setspecific");
121 typedef struct __darwin_pthread_handler_rec darwin_pthread_handler
;
126 ///////////////////////////////////////////////////////////////////////////////
129 * A thread-local object is a "global" object within a thread. This is useful
130 * for writing apartment-threaded code, where nothing is actually shared
131 * between different threads (hence no locking) but those variables are not
132 * on stack in local scope. To use it, just do something like this,
134 * THREAD_LOCAL(MyClass, static_object);
135 * static_object->data_ = ...;
136 * static_object->doSomething();
138 * THREAD_LOCAL(int, static_number);
139 * int value = *static_number;
141 * So, syntax-wise it's similar to pointers. The type parameter can be a
142 * primitive types. If it's a class, there has to be a default constructor.
145 ///////////////////////////////////////////////////////////////////////////////
146 #if defined(USE_GCC_FAST_TLS)
150 * We keep a linked list of destructors in ThreadLocalManager to be called on
151 * thread exit. ThreadLocalNode is a node in this list.
153 template <typename T
>
154 struct ThreadLocalNode
{
156 void (*m_on_thread_exit_fn
)(void * p
);
157 void (*m_init_tyindex
)(void*);
160 type_scan::Index m_tyindex
;
161 static void init_tyindex(void* node_ptr
) {
162 auto node
= static_cast<ThreadLocalNode
<T
>*>(node_ptr
);
163 node
->m_tyindex
= type_scan::getIndexForScan
<T
>();
167 struct ThreadLocalManager
{
169 static void PushTop(ThreadLocalNode
<T
>& node
) {
170 static_assert(sizeof(T
) <= 0xffffffffu
, "");
171 PushTop(&node
, sizeof(T
), type_scan::getIndexForScan
<T
>());
172 node
.m_init_tyindex
= &node
.init_tyindex
;
174 template<class Fn
> void iterate(Fn fn
) const;
175 void initTypeIndices();
176 static ThreadLocalManager
& GetManager();
179 static void PushTop(void* node
, uint32_t size
, type_scan::Index
);
180 struct ThreadLocalList
{
184 darwin_pthread_handler handler
;
187 static ThreadLocalList
* getList(void* p
) {
188 return static_cast<ThreadLocalList
*>(p
);
190 ThreadLocalManager() : m_key(0) {
192 ThreadLocalCreateKey(&m_key
, nullptr);
194 ThreadLocalCreateKey(&m_key
, ThreadLocalManager::OnThreadExit
);
197 static void OnThreadExit(void *p
);
201 ///////////////////////////////////////////////////////////////////////////////
202 // ThreadLocal allocates by calling new without parameters and frees by calling
206 void ThreadLocalOnThreadExit(void * p
) {
207 ThreadLocalNode
<T
> * pNode
= (ThreadLocalNode
<T
>*)p
;
209 pNode
->m_p
= nullptr;
213 * The USE_GCC_FAST_TLS implementation of ThreadLocal is just a lazy-initialized
214 * pointer wrapper. In this case, we have one ThreadLocal object per thread.
216 template<bool Check
, typename T
>
217 struct ThreadLocalImpl
{
219 NEVER_INLINE T
* getCheck() const {
223 T
* getNoCheck() const {
229 if (m_node
.m_p
== nullptr) {
230 const_cast<ThreadLocalImpl
<Check
,T
>*>(this)->create();
235 bool isNull() const { return m_node
.m_p
== nullptr; }
239 m_node
.m_p
= nullptr;
243 m_node
.m_p
= nullptr;
246 T
* operator->() const {
247 return Check
? get() : getNoCheck();
250 T
& operator*() const {
251 return Check
? *get() : *getNoCheck();
254 static size_t node_ptr_offset() {
255 using Self
= ThreadLocalImpl
<Check
,T
>;
256 return offsetof(Self
, m_node
) + offsetof(ThreadLocalNode
<T
>, m_p
);
260 NEVER_INLINE
void create();
261 ThreadLocalNode
<T
> m_node
;
264 template<bool Check
, typename T
>
265 void ThreadLocalImpl
<Check
,T
>::create() {
266 if (m_node
.m_on_thread_exit_fn
== nullptr) {
267 m_node
.m_on_thread_exit_fn
= ThreadLocalOnThreadExit
<T
>;
268 ThreadLocalManager::PushTop(m_node
);
270 assert(m_node
.m_p
== nullptr);
271 m_node
.m_p
= new T();
274 template<typename T
> using ThreadLocal
= ThreadLocalImpl
<true,T
>;
275 template<typename T
> using ThreadLocalNoCheck
= ThreadLocalImpl
<false,T
>;
277 ///////////////////////////////////////////////////////////////////////////////
278 // some classes don't need new/delete at all
281 struct ThreadLocalProxy
{
287 if (!m_node
.m_on_thread_exit_fn
) {
288 m_node
.m_on_thread_exit_fn
= onThreadExit
;
289 ThreadLocalManager::PushTop(m_node
);
293 assert(m_node
.m_p
== this);
298 bool isNull() const { return m_p
== nullptr; }
300 T
*operator->() const {
304 T
&operator*() const {
308 static void onThreadExit(void* p
) {
309 auto node
= (ThreadLocalNode
<ThreadLocalProxy
<T
>>*)p
;
314 ThreadLocalNode
<ThreadLocalProxy
<T
>> m_node
;
315 TYPE_SCAN_IGNORE_FIELD(m_node
);
318 // Wraps a __thread storage instance of T with a similar api to
319 // ThreadLocalProxy. Importantly, inlining a method of T via operator-> or
320 // operator* allows the C++ compiler to emit direct access to fields of
321 // T using the native thread-local segment pointer.
323 struct ThreadLocalFlat
{
324 T
* get() const { return (T
*)&m_value
; }
325 bool isNull() const { return !m_node
.m_p
; }
326 T
* getNoCheck() const { return get(); }
327 T
* operator->() const { return get(); }
328 T
& operator*() const { return *get(); }
329 explicit operator bool() const { return !isNull(); }
330 static void onThreadExit(void* p
) {
331 auto node
= (ThreadLocalNode
<ThreadLocalFlat
<T
>>*)p
;
332 auto value
= (T
*)&node
->m_p
->m_value
;
338 if (!m_node
.m_on_thread_exit_fn
) {
339 m_node
.m_on_thread_exit_fn
= onThreadExit
;
340 ThreadLocalManager::PushTop(m_node
);
345 assert(m_node
.m_p
== this);
346 assert(m_node
.m_on_thread_exit_fn
);
354 m_node
.m_p
= nullptr;
358 // We manage initialization explicitly
359 typename
std::aligned_storage
<sizeof(T
),alignof(T
)>::type m_value
;
360 ThreadLocalNode
<ThreadLocalFlat
<T
>> m_node
;
362 scanner
.scan(*get());
367 * How to use the thread-local macros:
369 * Use THREAD_LOCAL to declare a *static* class field or global as thread local:
371 * static THREAD_LOCAL(SomeFieldType, field);
373 * extern THREAD_LOCAL(SomeGlobal, tl_myglobal);
375 * Use THREAD_LOCAL in the cpp file to implement the field:
376 * THREAD_LOCAL(SomeFieldType, SomeClass::f);
377 * THREAD_LOCAL(SomeGlobal, tl_myglobal);
380 #define THREAD_LOCAL(T, f) __thread HPHP::ThreadLocal<T> f
381 #define THREAD_LOCAL_NO_CHECK(T, f) __thread HPHP::ThreadLocalNoCheck<T> f
382 #define THREAD_LOCAL_PROXY(T, f) __thread HPHP::ThreadLocalProxy<T> f
383 #define THREAD_LOCAL_FLAT(T, f) __thread HPHP::ThreadLocalFlat<T> f
387 #else /* USE_GCC_FAST_TLS */
388 #include "hphp/util/thread-local-emulate.h"
389 #endif /* USE_GCC_FAST_TLS */
391 ///////////////////////////////////////////////////////////////////////////////
393 #endif // incl_HPHP_THREAD_LOCAL_H_