Optional Two-phase heap tracing
[hiphop-php.git] / hphp / util / thread-local.h
blob7bbb73d185a4b9e01fe6a8a7bffa3503b14171ef
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/exception.h"
27 #include "hphp/util/type-scan.h"
29 namespace HPHP {
31 // return the location of the current thread's tdata section
32 std::pair<void*,size_t> getCppTdata();
34 #ifdef _MSC_VER
35 extern "C" int _tls_index;
36 #endif
38 inline uintptr_t tlsBase() {
39 uintptr_t retval;
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"
48 "or %0,%0,13\n\t"
49 : "=r" (retval));
50 #elif defined(_M_X64)
51 retval = (uintptr_t)__readgsqword(88);
52 retval = *(uintptr_t*)(retval + (_tls_index * 8));
53 #else
54 # error How do you access thread-local storage on this machine?
55 #endif
56 return retval;
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
77 // types
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
95 #endif
97 ///////////////////////////////////////////////////////////////////////////////
98 // helper
100 inline void ThreadLocalCheckReturn(int ret, const char *funcName) {
101 if (ret != 0) {
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());
106 exit(1);
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");
120 #ifdef __APPLE__
121 typedef struct __darwin_pthread_handler_rec darwin_pthread_handler;
122 #endif
124 } // namespace HPHP
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)
148 namespace HPHP {
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 {
155 T* m_p;
156 void (*m_on_thread_exit_fn)(void * p);
157 void (*m_init_tyindex)(void*);
158 void* m_next;
159 uint32_t m_size;
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 {
168 template<class T>
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();
178 private:
179 static void PushTop(void* node, uint32_t size, type_scan::Index);
180 struct ThreadLocalList {
181 void* head{nullptr};
182 #ifdef __APPLE__
183 ThreadLocalList();
184 darwin_pthread_handler handler;
185 #endif
187 static ThreadLocalList* getList(void* p) {
188 return static_cast<ThreadLocalList*>(p);
190 ThreadLocalManager() : m_key(0) {
191 #ifdef __APPLE__
192 ThreadLocalCreateKey(&m_key, nullptr);
193 #else
194 ThreadLocalCreateKey(&m_key, ThreadLocalManager::OnThreadExit);
195 #endif
197 static void OnThreadExit(void *p);
198 pthread_key_t m_key;
201 ///////////////////////////////////////////////////////////////////////////////
202 // ThreadLocal allocates by calling new without parameters and frees by calling
203 // delete
205 template<typename T>
206 void ThreadLocalOnThreadExit(void * p) {
207 ThreadLocalNode<T> * pNode = (ThreadLocalNode<T>*)p;
208 delete pNode->m_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 {
220 return get();
223 T* getNoCheck() const {
224 assert(m_node.m_p);
225 return m_node.m_p;
228 T* get() const {
229 if (m_node.m_p == nullptr) {
230 const_cast<ThreadLocalImpl<Check,T>*>(this)->create();
232 return m_node.m_p;
235 bool isNull() const { return m_node.m_p == nullptr; }
237 void destroy() {
238 delete m_node.m_p;
239 m_node.m_p = nullptr;
242 void nullOut() {
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);
259 private:
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
280 template<typename T>
281 struct ThreadLocalProxy {
282 T *get() const {
283 return m_p;
286 void set(T* obj) {
287 if (!m_node.m_on_thread_exit_fn) {
288 m_node.m_on_thread_exit_fn = onThreadExit;
289 ThreadLocalManager::PushTop(m_node);
290 assert(!m_node.m_p);
291 m_node.m_p = this;
292 } else {
293 assert(m_node.m_p == this);
295 m_p = obj;
298 bool isNull() const { return m_p == nullptr; }
300 T *operator->() const {
301 return get();
304 T &operator*() const {
305 return *get();
308 static void onThreadExit(void* p) {
309 auto node = (ThreadLocalNode<ThreadLocalProxy<T>>*)p;
310 node->m_p = nullptr;
313 T* m_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.
322 template<typename T>
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;
333 value->~T();
334 node->m_p = nullptr;
336 T* getCheck() {
337 if (!m_node.m_p) {
338 if (!m_node.m_on_thread_exit_fn) {
339 m_node.m_on_thread_exit_fn = onThreadExit;
340 ThreadLocalManager::PushTop(m_node);
342 new (&m_value) T();
343 m_node.m_p = this;
344 } else {
345 assert(m_node.m_p == this);
346 assert(m_node.m_on_thread_exit_fn);
348 return get();
351 void destroy() {
352 if (m_node.m_p) {
353 get()->~T();
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;
361 TYPE_SCAN_CUSTOM() {
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:
370 * struct SomeClass {
371 * static THREAD_LOCAL(SomeFieldType, field);
372 * };
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
385 } // namespace HPHP
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_