Logo ROOT   master
Reference Guide
ThreadLocalStorage.h
Go to the documentation of this file.
1 // @(#)root/thread:$Id$
2 /*
3  * Copyright (c) 2006-2011 High Performance Computing Center Stuttgart,
4  * University of Stuttgart. All rights reserved.
5  * Author: Rainer Keller, HLRS
6  * Modified: Fons Rademakers, CERN
7  * Modified: Philippe Canal, FNAL
8  *
9  * Thread-local storage (TLS) is not supported on all environments.
10  * This header file and test-program shows how to abstract away, using either
11  * __thread,
12  * __declspec(thread),
13  * thread_local or
14  * Pthread-Keys
15  * depending on the (configure-set) CPP-variables R__HAS___THREAD,
16  * R__HAS_DECLSPEC_THREAD, R__HAS_THREAD_LOCAL or R__HAS_PTHREAD.
17  *
18  * Use the macros TTHREAD_TLS_DECLARE, TTHREAD_TLS_INIT, and the
19  * getters and setters TTHREAD_TLS_GET and TTHREAD_TLS_GET
20  * to work on the declared variables.
21  *
22  * In case of PThread keys, we need to resolve to using keys!
23  * In order to do so, we need to declare and access
24  * TLS variables through three macros:
25  * - TTHREAD_TLS_DECLARE
26  * - TTHREAD_TLS_INIT
27  * - TTHREAD_TLS_SET and
28  * - TTHREAD_TLS_GET
29  * We do depend on the following (GCC-)extension:
30  * - In case of function-local static functions,
31  * we declare a sub-function to create a specific key.
32  * Unfortunately, we do NOT use the following extensions:
33  * - Using typeof, we could get rid of the type-declaration
34  * which is used for casting, however typeof is not ANSI C.
35  * - We do NOT allow something like
36  * func (a, TTHREAD_TLS_SET(int, my_var, 5));
37  * as we do not use the gcc-extension of returning macro-values.
38  *
39  * C++11 requires the implementation of the thread_local storage but
40  * a few platforms do not yet implement it.
41  *
42  * For simple type use:
43  * TTHREAD_TLS(int) varname;
44  *
45  * For array of simple type use:
46  * TTHREAD_TLS_ARRAY(int, arraysize, varname);
47  *
48  * For object use:
49  * TTHREAD_TLS_DECL(classname, varname);
50  * TTHREAD_TLS_DECL_ARG(classname, varname, arg);
51  * TTHREAD_TLS_DECL_ARG2(classname, varname, arg1, arg2);
52  *
53  */
54 
55 #ifndef ROOT_ThreadLocalStorage
56 #define ROOT_ThreadLocalStorage
57 
58 #include <stddef.h>
59 
60 #ifdef __cplusplus
61 #include "RtypesCore.h"
62 #endif
63 
64 #include <ROOT/RConfig.hxx>
65 
66 #include "RConfigure.h"
67 
68 #if defined(R__MACOSX)
69 # if defined(__clang__) && defined(MAC_OS_X_VERSION_10_7) && (defined(__x86_64__) || defined(__i386__))
70 # define R__HAS___THREAD
71 # elif !defined(R__HAS_PTHREAD)
72 # define R__HAS_PTHREAD
73 # endif
74 #endif
75 #if defined(R__LINUX) || defined(R__AIX)
76 # define R__HAS___THREAD
77 #endif
78 #if defined(R__SOLARIS) && !defined(R__HAS_PTHREAD)
79 # define R__HAS_PTHREAD
80 #endif
81 #if defined(R__WIN32)
82 # define R__HAS_DECLSPEC_THREAD
83 #endif
84 
85 #if __cplusplus >= 201103L
86 
87 // Clang 3.4 also support SD-6 (feature test macros __cpp_*), but no thread local macro
88 # if defined(__clang__)
89 
90 # if __has_feature(cxx_thread_local)
91  // thread_local was added in Clang 3.3
92  // Still requires libstdc++ from GCC 4.8
93  // For that __GLIBCXX__ isn't good enough
94  // Also the MacOS build of clang does *not* support thread local yet.
95 # define R__HAS_THREAD_LOCAL
96 # else
97 # define R__HAS___THREAD
98 # endif
99 
100 # elif defined(__INTEL_COMPILER)
101 # define R__HAS__THREAD
102 
103 # elif defined(__GNUG__) && (__GNUC__ <= 4 && __GNUC_MINOR__ < 8)
104  // The C++11 thread_local keyword is supported in GCC only since 4.8
105 # define R__HAS___THREAD
106 # else
107 # define R__HAS_THREAD_LOCAL
108 # endif
109 
110 #endif
111 
112 
113 #ifdef __cplusplus
114 
115 // Note that the order is relevant, more than one of the flag might be
116 // on at the same time and we want to use 'best' option available.
117 
118 #ifdef __CINT__
119 
120 # define TTHREAD_TLS(type) static type
121 # define TTHREAD_TLS_ARRAY(type,size,name) static type name[size]
122 # define TTHREAD_TLS_PTR(name) &name
123 
124 #elif defined(R__HAS_THREAD_LOCAL)
125 
126 # define TTHREAD_TLS(type) thread_local type
127 # define TTHREAD_TLS_ARRAY(type,size,name) thread_local type name[size]
128 # define TTHREAD_TLS_PTR(name) &name
129 
130 # define TTHREAD_TLS_DECL(type, name) thread_local type name
131 # define TTHREAD_TLS_DECL_ARG(type, name, arg) thread_local type name(arg)
132 # define TTHREAD_TLS_DECL_ARG2(type, name, arg1, arg2) thread_local type name(arg1,arg2)
133 
134 #elif defined(R__HAS___THREAD)
135 
136 # define TTHREAD_TLS(type) static __thread type
137 # define TTHREAD_TLS_ARRAY(type,size,name) static __thread type name[size]
138 # define TTHREAD_TLS_PTR(name) &name
139 
140 #elif defined(R__HAS_DECLSPEC_THREAD)
141 
142 # define TTHREAD_TLS(type) static __declspec(thread) type
143 # define TTHREAD_TLS_ARRAY(type,size,name) static __declspec(thread) type name[size]
144 # define TTHREAD_TLS_PTR(name) &name
145 
146 #elif defined(R__HAS_PTHREAD)
147 
148 #include <assert.h>
149 #include <pthread.h>
150 
151 template <typename type> class TThreadTLSWrapper
152 {
153 private:
154  pthread_key_t fKey;
155  type fInitValue;
156 
157  static void key_delete(void *arg) {
158  assert (NULL != arg);
159  delete (type*)(arg);
160  }
161 
162 public:
163 
164  TThreadTLSWrapper() : fInitValue() {
165 
166  pthread_key_create(&(fKey), key_delete);
167  }
168 
169  TThreadTLSWrapper(const type &value) : fInitValue(value) {
170 
171  pthread_key_create(&(fKey), key_delete);
172  }
173 
174  ~TThreadTLSWrapper() {
175  pthread_key_delete(fKey);
176  }
177 
178  type& get() {
179  void *ptr = pthread_getspecific(fKey);
180  if (!ptr) {
181  ptr = new type(fInitValue);
182  assert (NULL != ptr);
183  (void) pthread_setspecific(fKey, ptr);
184  }
185  return *(type*)ptr;
186  }
187 
188  type& operator=(const type &in) {
189  type &ptr = get();
190  ptr = in;
191  return ptr;
192  }
193 
194  operator type&() {
195  return get();
196  }
197 
198 };
199 
200 template <typename type,int size> class TThreadTLSArrayWrapper
201 {
202 private:
203  pthread_key_t fKey;
204 
205  static void key_delete(void *arg) {
206  assert (NULL != arg);
207  delete [] (type*)(arg);
208  }
209 
210 public:
211 
212  TThreadTLSArrayWrapper() {
213 
214  pthread_key_create(&(fKey), key_delete);
215  }
216 
217  ~TThreadTLSArrayWrapper() {
218  pthread_key_delete(fKey);
219  }
220 
221  type* get() {
222  void *ptr = pthread_getspecific(fKey);
223  if (!ptr) {
224  ptr = new type[size];
225  assert (NULL != ptr);
226  (void) pthread_setspecific(fKey, ptr);
227  }
228  return (type*)ptr;
229  }
230 
231 // type& operator=(const type &in) {
232 // type &ptr = get();
233 // ptr = in;
234 // return ptr;
235 // }
236 //
237  operator type*() {
238  return get();
239  }
240 
241 };
242 
243 # define TTHREAD_TLS(type) static TThreadTLSWrapper<type>
244 # define TTHREAD_TLS_ARRAY(type,size,name) static TThreadTLSArrayWrapper<type,size> name;
245 # define TTHREAD_TLS_PTR(name) &(name.get())
246 # define TTHREAD_TLS_OBJ(index,type,name) type &name( TTHREAD_TLS_INIT<index,type>() )
247 
248 #else
249 
250 #error "No Thread Local Storage (TLS) technology for this platform specified."
251 
252 #endif
253 
254 // Available on all platforms
255 
256 
257 // Neither TTHREAD_TLS_DECL_IMPL and TTHREAD_TLS_INIT
258 // do not delete the object at the end of the process.
259 
260 #define TTHREAD_TLS_DECL_IMPL(type, name, ptr, arg) \
261  TTHREAD_TLS(type *) ptr = 0; \
262  if (!ptr) ptr = new type(arg); \
263  type &name = *ptr;
264 
265 #define TTHREAD_TLS_DECL_IMPL2(type, name, ptr, arg1, arg2) \
266  TTHREAD_TLS(type *) ptr = 0; \
267  if (!ptr) ptr = new type(arg1,arg2); \
268  type &name = *ptr;
269 
270 #ifndef TTHREAD_TLS_DECL
271 
272 #define TTHREAD_TLS_DECL(type, name) \
273  TTHREAD_TLS_DECL_IMPL(type,name,_R__JOIN_(ptr,__LINE__),)
274 
275 #define TTHREAD_TLS_DECL_ARG(type, name, arg) \
276  TTHREAD_TLS_DECL_IMPL(type,name,_R__JOIN_(ptr,__LINE__),arg)
277 
278 #define TTHREAD_TLS_DECL_ARG2(type, name, arg1, arg2) \
279  TTHREAD_TLS_DECL_IMPL2(type,name,_R__JOIN_(ptr,__LINE__),arg1,arg2)
280 
281 #endif
282 
283 template <int marker, typename T>
284 T &TTHREAD_TLS_INIT() {
285  TTHREAD_TLS(T*) ptr = NULL;
286  TTHREAD_TLS(Bool_t) isInit(kFALSE);
287  if (!isInit) {
288  ptr = new T;
289  isInit = kTRUE;
290  }
291  return *ptr;
292 }
293 
294 template <int marker, typename Array, typename T>
295 Array &TTHREAD_TLS_INIT_ARRAY() {
296  TTHREAD_TLS(Array*) ptr = NULL;
297  TTHREAD_TLS(Bool_t) isInit(kFALSE);
298  if (!isInit) {
299  ptr = new Array[sizeof(Array)/sizeof(T)];
300  isInit = kTRUE;
301  }
302  return *ptr;
303 }
304 
305 template <int marker, typename T, typename ArgType>
306 T &TTHREAD_TLS_INIT(ArgType arg) {
307  TTHREAD_TLS(T*) ptr = NULL;
308  TTHREAD_TLS(Bool_t) isInit(kFALSE);
309  if (!isInit) {
310  ptr = new T(arg);
311  isInit = kTRUE;
312  }
313  return *ptr;
314 }
315 
316 #else // __cplusplus
317 
318 #if defined(R__HAS_THREAD_LOCAL)
319 
320 # define TTHREAD_TLS_DECLARE(type,name)
321 # define TTHREAD_TLS_INIT(type,name,value) thread_local type name = (value)
322 # define TTHREAD_TLS_SET(type,name,value) name = (value)
323 # define TTHREAD_TLS_GET(type,name) (name)
324 # define TTHREAD_TLS_FREE(name)
325 
326 #elif defined(R__HAS___THREAD)
327 
328 # define TTHREAD_TLS_DECLARE(type,name)
329 # define TTHREAD_TLS_INIT(type,name,value) static __thread type name = (value)
330 # define TTHREAD_TLS_SET(type,name,value) name = (value)
331 # define TTHREAD_TLS_GET(type,name) (name)
332 # define TTHREAD_TLS_FREE(name)
333 
334 #elif defined(R__HAS_DECLSPEC_THREAD)
335 
336 # define TTHREAD_TLS_DECLARE(type,name)
337 # define TTHREAD_TLS_INIT(type,name,value) static __declspec(thread) type name = (value)
338 # define TTHREAD_TLS_SET(type,name,value) name = (value)
339 # define TTHREAD_TLS_GET(type,name) (name)
340 # define TTHREAD_TLS_FREE(name)
341 
342 #elif defined(R__HAS_PTHREAD)
343 
344 #include <assert.h>
345 #include <pthread.h>
346 
347 # define TTHREAD_TLS_DECLARE(type,name) \
348  static pthread_key_t _##name##_key; \
349  static void _##name##_key_delete(void * arg) \
350  { \
351  assert (NULL != arg); \
352  free(arg); \
353  } \
354  static void _##name##_key_create(void) \
355  { \
356  int _ret; \
357  _ret = pthread_key_create(&(_##name##_key), _##name##_key_delete); \
358  _ret = _ret; /* To get rid of warnings in case of NDEBUG */ \
359  assert (0 == _ret); \
360  } \
361  static pthread_once_t _##name##_once = PTHREAD_ONCE_INIT;
362 
363 # define TTHREAD_TLS_INIT(type,name,value) \
364  do { \
365  void *_ptr; \
366  (void) pthread_once(&(_##name##_once), _##name##_key_create); \
367  if ((_ptr = pthread_getspecific(_##name##_key)) == NULL) { \
368  _ptr = malloc(sizeof(type)); \
369  assert (NULL != _ptr); \
370  (void) pthread_setspecific(_##name##_key, _ptr); \
371  *((type*)_ptr) = (value); \
372  } \
373  } while (0)
374 
375 # define TTHREAD_TLS_SET(type,name,value) \
376  do { \
377  void *_ptr = pthread_getspecific(_##name##_key); \
378  assert (NULL != _ptr); \
379  *((type*)_ptr) = (value); \
380  } while (0)
381 
382 # define TTHREAD_TLS_GET(type,name) \
383  *((type*)pthread_getspecific(_##name##_key))
384 
385 # define TTHREAD_TLS_FREE(name) \
386  pthread_key_delete(_##name##_key);
387 
388 #else
389 
390 #error "No Thread Local Storage (TLS) technology for this platform specified."
391 
392 #endif
393 
394 #endif // __cplusplus
395 
396 #endif
397 
double T(double x)
Definition: ChebyshevPol.h:34
bool Bool_t
Definition: RtypesCore.h:61
const char * Array
const Bool_t kFALSE
Definition: RtypesCore.h:90
int type
Definition: TGX11.cxx:120
Binding & operator=(OUT(*fun)(void))
typedef void((*Func_t)())
const Bool_t kTRUE
Definition: RtypesCore.h:89