enable coroutine for rust emitter
[hiphop-php.git] / hphp / util / thread-local.h
blobbbea35002518a5db0f7a69a921202e9048f792c1
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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_
20 #include <cerrno>
21 #include <pthread.h>
22 #include <type_traits>
24 #include <folly/String.h>
26 #include "hphp/util/alloc.h"
27 #include "hphp/util/exception.h"
28 #include "hphp/util/type-scan.h"
30 namespace HPHP {
32 // return the location of the current thread's tdata section
33 std::pair<void*,size_t> getCppTdata();
35 #ifdef _MSC_VER
36 extern "C" int _tls_index;
37 #endif
39 inline uintptr_t tlsBase() {
40 uintptr_t retval;
41 #if defined(__x86_64__)
42 asm ("movq %%fs:0, %0" : "=r" (retval));
43 #elif defined(__AARCH64EL__)
44 // mrs == "move register <-- system"
45 // tpidr_el0 == "thread process id register for exception level 0"
46 asm ("mrs %0, tpidr_el0" : "=r" (retval));
47 #elif defined (__powerpc64__)
48 asm ("xor %0,%0,%0\n\t"
49 "or %0,%0,13\n\t"
50 : "=r" (retval));
51 #elif defined(_M_X64)
52 retval = (uintptr_t)__readgsqword(88);
53 retval = *(uintptr_t*)(retval + (_tls_index * 8));
54 #else
55 # error How do you access thread-local storage on this machine?
56 #endif
57 return retval;
60 ///////////////////////////////////////////////////////////////////////////////
61 // gcc >= 4.3.0 supports the '__thread' keyword for thread locals
63 // Clang seems to have added this feature, or at the very least it is ignoring
64 // __thread keyword and compiling anyway
66 // On OSX, gcc does emulate TLS but in a manner that invalidates assumptions
67 // we have made about __thread and makes accessing thread-local variables in a
68 // JIT-friendly fashion difficult (as the compiler is doing a lot of magic that
69 // is not contractual or documented that we would need to duplicate in emitted
70 // code) so for now we're not going to use it. One possibility if we really
71 // want to do this is to generate functions that access variables of interest
72 // in ThreadLocal* (all of them are NoCheck right now) and use the bytes of
73 // gcc's compiled functions to find the values we would need to pass to
74 // __emutls_get_address.
76 // icc 13.0.0 appears to support it as well but we end up with
77 // assembler warnings of unknown importance about incorrect section
78 // types
80 // __thread on cygwin and mingw uses pthreads emulation not native tls so
81 // the emulation for thread local must be used as well
83 // So we use __thread on gcc, icc and clang, and OSX, falling back to
84 // emulation on unsupported platforms. Use the THREAD_LOCAL() macro to
85 // hide the decl details.
87 // See thread-local-emulate.h for the emulated versions; they're in a
88 // separate header to avoid confusion; this is a long header file and it's
89 // easy to lose track of which version you're looking at.
91 #if !defined(NO_TLS) && \
92 ((__llvm__ && __clang__) || \
93 __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 3) || \
94 __INTEL_COMPILER || defined(_MSC_VER))
95 #define USE_GCC_FAST_TLS
96 #endif
98 ///////////////////////////////////////////////////////////////////////////////
99 // helper
101 inline void ThreadLocalCheckReturn(int ret, const char *funcName) {
102 if (ret != 0) {
103 // This is used from global constructors so the safest thing to do is just
104 // print to stderr and exit().
105 fprintf(stderr, "%s returned %d: %s", funcName, ret,
106 folly::errnoStr(ret).c_str());
107 exit(1);
111 inline void ThreadLocalCreateKey(pthread_key_t *key, void (*del)(void*)) {
112 int ret = pthread_key_create(key, del);
113 ThreadLocalCheckReturn(ret, "pthread_key_create");
116 inline void ThreadLocalSetValue(pthread_key_t key, const void* value) {
117 int ret = pthread_setspecific(key, value);
118 ThreadLocalCheckReturn(ret, "pthread_setspecific");
121 #ifdef __APPLE__
122 typedef struct __darwin_pthread_handler_rec darwin_pthread_handler;
123 #endif
125 } // namespace HPHP
127 ///////////////////////////////////////////////////////////////////////////////
130 * A thread-local object is a "global" object within a thread. This is useful
131 * for writing apartment-threaded code, where nothing is actually shared
132 * between different threads (hence no locking) but those variables are not
133 * on stack in local scope. To use it, just do something like this,
135 * THREAD_LOCAL(MyClass, static_object);
136 * static_object->data_ = ...;
137 * static_object->doSomething();
139 * THREAD_LOCAL(int, static_number);
140 * int value = *static_number;
142 * So, syntax-wise it's similar to pointers. The type parameter can be a
143 * primitive types. If it's a class, there has to be a default constructor.
146 ///////////////////////////////////////////////////////////////////////////////
147 #if defined(USE_GCC_FAST_TLS)
149 namespace HPHP {
151 * We keep a linked list of destructors in ThreadLocalManager to be called on
152 * thread exit. ThreadLocalNode is a node in this list.
154 template <typename T>
155 struct ThreadLocalNode {
156 T* m_p;
157 void (*m_on_thread_exit_fn)(void * p);
158 void (*m_init_tyindex)(void*);
159 void* m_next;
160 uint32_t m_size;
161 type_scan::Index m_tyindex;
162 static void init_tyindex(void* node_ptr) {
163 auto node = static_cast<ThreadLocalNode<T>*>(node_ptr);
164 node->m_tyindex = type_scan::getIndexForScan<T>();
168 struct ThreadLocalManager {
169 template<class T>
170 static void PushTop(ThreadLocalNode<T>& node) {
171 static_assert(sizeof(T) <= 0xffffffffu, "");
172 PushTop(&node, sizeof(T), type_scan::getIndexForScan<T>());
173 node.m_init_tyindex = &node.init_tyindex;
175 template<class Fn> void iterate(Fn fn) const;
176 void initTypeIndices();
177 static ThreadLocalManager& GetManager();
179 private:
180 static void PushTop(void* node, uint32_t size, type_scan::Index);
181 struct ThreadLocalList {
182 void* head{nullptr};
183 #ifdef __APPLE__
184 ThreadLocalList();
185 darwin_pthread_handler handler;
186 #endif
188 static ThreadLocalList* getList(void* p) {
189 return static_cast<ThreadLocalList*>(p);
191 ThreadLocalManager() : m_key(0) {
192 #ifdef __APPLE__
193 ThreadLocalCreateKey(&m_key, nullptr);
194 #else
195 ThreadLocalCreateKey(&m_key, ThreadLocalManager::OnThreadExit);
196 #endif
198 static void OnThreadExit(void *p);
199 pthread_key_t m_key;
202 ///////////////////////////////////////////////////////////////////////////////
203 // ThreadLocal allocates in the local arena, created using local_malloc()
204 // followed by placement new and destroyed by calling destructor followed by
205 // local_free() delete.
207 template<typename T>
208 void ThreadLocalOnThreadExit(void * p) {
209 auto pNode = (ThreadLocalNode<T>*)p;
210 if (pNode->m_p) {
211 pNode->m_p->~T();
212 local_free(pNode->m_p);
213 pNode->m_p = nullptr;
218 * The USE_GCC_FAST_TLS implementation of ThreadLocal is just a lazy-initialized
219 * pointer wrapper. In this case, we have one ThreadLocal object per thread.
221 template<bool Check, typename T>
222 struct ThreadLocalImpl {
224 NEVER_INLINE T* getCheck() const {
225 return get();
228 T* getNoCheck() const {
229 assert(m_node.m_p);
230 return m_node.m_p;
233 T* get() const {
234 if (m_node.m_p == nullptr) {
235 const_cast<ThreadLocalImpl<Check,T>*>(this)->create();
237 return m_node.m_p;
240 bool isNull() const { return m_node.m_p == nullptr; }
242 void destroy() {
243 if (m_node.m_p) {
244 m_node.m_p->~T();
245 local_free(m_node.m_p);
246 m_node.m_p = nullptr;
250 void nullOut() {
251 m_node.m_p = nullptr;
254 T* operator->() const {
255 return Check ? get() : getNoCheck();
258 T& operator*() const {
259 return Check ? *get() : *getNoCheck();
262 static size_t node_ptr_offset() {
263 using Self = ThreadLocalImpl<Check,T>;
264 return offsetof(Self, m_node) + offsetof(ThreadLocalNode<T>, m_p);
267 private:
268 NEVER_INLINE void create();
269 ThreadLocalNode<T> m_node;
272 template<bool Check, typename T>
273 void ThreadLocalImpl<Check,T>::create() {
274 if (m_node.m_on_thread_exit_fn == nullptr) {
275 m_node.m_on_thread_exit_fn = ThreadLocalOnThreadExit<T>;
276 ThreadLocalManager::PushTop(m_node);
278 assert(m_node.m_p == nullptr);
279 m_node.m_p = new (local_malloc(sizeof(T))) T();
282 template<typename T> using ThreadLocal = ThreadLocalImpl<true,T>;
283 template<typename T> using ThreadLocalNoCheck = ThreadLocalImpl<false,T>;
285 // Wraps a __thread storage instance of T with a similar api to
286 // ThreadLocalProxy. Importantly, inlining a method of T via operator-> or
287 // operator* allows the C++ compiler to emit direct access to fields of
288 // T using the native thread-local segment pointer.
289 template<typename T>
290 struct ThreadLocalFlat {
291 T* get() const { return (T*)&m_value; }
292 bool isNull() const { return !m_node.m_p; }
293 T* getNoCheck() const { return get(); }
294 T* operator->() const { return get(); }
295 T& operator*() const { return *get(); }
296 explicit operator bool() const { return !isNull(); }
297 static void onThreadExit(void* p) {
298 auto node = (ThreadLocalNode<ThreadLocalFlat<T>>*)p;
299 if (node->m_p) {
300 auto value = (T*)&node->m_p->m_value;
301 value->~T();
302 node->m_p = nullptr;
305 T* getCheck() {
306 if (!m_node.m_p) {
307 if (!m_node.m_on_thread_exit_fn) {
308 m_node.m_on_thread_exit_fn = onThreadExit;
309 ThreadLocalManager::PushTop(m_node);
311 new (&m_value) T();
312 m_node.m_p = this;
313 } else {
314 assert(m_node.m_p == this);
315 assert(m_node.m_on_thread_exit_fn);
317 return get();
320 void destroy() {
321 if (m_node.m_p) {
322 get()->~T();
323 m_node.m_p = nullptr;
327 // We manage initialization explicitly
328 typename std::aligned_storage<sizeof(T),alignof(T)>::type m_value;
329 ThreadLocalNode<ThreadLocalFlat<T>> m_node;
330 TYPE_SCAN_CUSTOM() {
331 scanner.scan(*get());
336 * How to use the thread-local macros:
338 * Use THREAD_LOCAL to declare a *static* class field or global as thread local:
339 * struct SomeClass {
340 * static THREAD_LOCAL(SomeFieldType, field);
341 * };
342 * extern THREAD_LOCAL(SomeGlobal, tl_myglobal);
344 * Use THREAD_LOCAL in the cpp file to implement the field:
345 * THREAD_LOCAL(SomeFieldType, SomeClass::f);
346 * THREAD_LOCAL(SomeGlobal, tl_myglobal);
349 #define THREAD_LOCAL(T, f) __thread HPHP::ThreadLocal<T> f
350 #define THREAD_LOCAL_NO_CHECK(T, f) __thread HPHP::ThreadLocalNoCheck<T> f
351 #define THREAD_LOCAL_FLAT(T, f) __thread HPHP::ThreadLocalFlat<T> f
353 } // namespace HPHP
355 #else /* USE_GCC_FAST_TLS */
356 #include "hphp/util/thread-local-emulate.h"
357 #endif /* USE_GCC_FAST_TLS */
359 ///////////////////////////////////////////////////////////////////////////////
361 #endif // incl_HPHP_THREAD_LOCAL_H_