1 //===- subzero/src/IceTLS.h - thread_local workaround -----------*- C++ -*-===//
2 //
3 //                        The Subzero Code Generator
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief Defines macros for working around the lack of support for
12 /// thread_local in MacOS 10.6.
13 ///
14 /// This assumes std::thread is written in terms of pthread. Define
15 /// ICE_THREAD_LOCAL_HACK to enable the pthread workarounds.
16 ///
17 //===----------------------------------------------------------------------===//
18 
19 #ifndef SUBZERO_SRC_ICETLS_H
20 #define SUBZERO_SRC_ICETLS_H
21 
22 ///
23 /// @defgroup /IceTLS Defines 5 macros for unifying thread_local and pthread:
24 /// @{
25 ///
26 /// \def ICE_TLS_DECLARE_FIELD(Type, FieldName)
27 /// Declare a static thread_local field inside the current class definition.
28 /// "Type" needs to be a pointer type, such as int* or class Foo*.
29 ///
30 /// \def ICE_TLS_DEFINE_FIELD(Type, ClassName, FieldName)
31 /// Define a static thread_local field outside of its class definition. The
32 /// field will ultimately be initialized to nullptr.
33 ///
34 /// \def ICE_TLS_INIT_FIELD(FieldName)
35 /// Ensure the thread_local field is properly initialized. This is intended
36 /// to be called from within a static method of the field's class after main()
37 /// starts (to ensure that the pthread library is fully initialized) but before
38 /// any uses of ICE_TLS_GET_FIELD or ICE_TLS_SET_FIELD.
39 ///
40 /// \def ICE_TLS_GET_FIELD(Type, FieldName)
41 /// Read the value of the static thread_local field. Must be done within the
42 /// context of its class.
43 ///
44 /// \def ICE_TLS_SET_FIELD(FieldName, Value)
45 /// Write a value into the static thread_local field. Must be done within the
46 /// context of its class.
47 
48 /// TODO(stichnot): Limit this define to only the platforms that absolutely
49 /// require it. And ideally, eventually remove this hack altogether.
50 ///
51 
52 ///
53 /// \def ICE_THREAD_LOCAL_HACK
54 ///
55 #ifndef ICE_THREAD_LOCAL_HACK
56 #define ICE_THREAD_LOCAL_HACK 1
57 #endif
58 
59 #if ICE_THREAD_LOCAL_HACK
60 
61 // For a static thread_local field F of a class C, instead of declaring and
62 // defining C::F, we create two static fields:
63 //   static pthread_key_t F__key;
64 //   static int F__initStatus;
65 //
66 // The F__initStatus field is used to hold the result of the
67 // pthread_key_create() call, where a zero value indicates success, and a
68 // nonzero value indicates failure or that ICE_TLS_INIT_FIELD() was never
69 // called. The F__key field is used as the argument to pthread_getspecific()
70 // and pthread_setspecific().
71 
72 #include "llvm/Support/ErrorHandling.h"
73 
74 #include <pthread.h>
75 
76 #define ICE_TLS_DECLARE_FIELD(Type, FieldName)                                 \
77   using FieldName##__type = Type;                                              \
78   static pthread_key_t FieldName##__key;                                       \
79   static int FieldName##__initStatus
80 #define ICE_TLS_DEFINE_FIELD(Type, ClassName, FieldName)                       \
81   pthread_key_t ClassName::FieldName##__key;                                   \
82   int ClassName::FieldName##__initStatus = 1
83 #define ICE_TLS_INIT_FIELD(FieldName)                                          \
84   if (FieldName##__initStatus) {                                               \
85     FieldName##__initStatus = pthread_key_create(&FieldName##__key, nullptr);  \
86     if (FieldName##__initStatus)                                               \
87       llvm::report_fatal_error("Failed to create pthread key");                \
88   }
89 #define ICE_TLS_GET_FIELD(FieldName)                                           \
90   (assert(FieldName##__initStatus == 0),                                       \
91    static_cast<FieldName##__type>(pthread_getspecific(FieldName##__key)))
92 #define ICE_TLS_SET_FIELD(FieldName, Value)                                    \
93   (assert(FieldName##__initStatus == 0),                                       \
94    pthread_setspecific(FieldName##__key, (Value)))
95 
96 #else // !ICE_THREAD_LOCAL_HACK
97 
98 #if defined(_MSC_VER)
99 #define ICE_ATTRIBUTE_TLS __declspec(thread)
100 #else // !_MSC_VER
101 #define ICE_ATTRIBUTE_TLS thread_local
102 #endif // !_MSC_VER
103 
104 #define ICE_TLS_DECLARE_FIELD(Type, FieldName)                                 \
105   static ICE_ATTRIBUTE_TLS Type FieldName
106 #define ICE_TLS_DEFINE_FIELD(Type, ClassName, FieldName)                       \
107   ICE_ATTRIBUTE_TLS Type ClassName::FieldName = nullptr
108 #define ICE_TLS_INIT_FIELD(FieldName)
109 #define ICE_TLS_GET_FIELD(FieldName) (FieldName)
110 #define ICE_TLS_SET_FIELD(FieldName, Value) (FieldName = (Value))
111 
112 #endif // !ICE_THREAD_LOCAL_HACK
113 
114 ///
115 /// @}
116 ///
117 
118 #endif // SUBZERO_SRC_ICETLS_H
119