Logo ROOT   6.08/07
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 "Rtypes.h"
62 #endif
63 
64 #ifndef ROOT_RConfig
65 #include "RConfig.h"
66 #endif
67 
68 #ifndef ROOT_RConfigure
69 #include "RConfigure.h"
70 #endif
71 
72 #if defined(R__MACOSX)
73 # if defined(__clang__) && defined(MAC_OS_X_VERSION_10_7) && (defined(__x86_64__) || defined(__i386__))
74 # define R__HAS___THREAD
75 # elif !defined(R__HAS_PTHREAD)
76 # define R__HAS_PTHREAD
77 # endif
78 #endif
79 #if defined(R__LINUX) || defined(R__AIX)
80 # define R__HAS___THREAD
81 #endif
82 #if defined(R__SOLARIS) && !defined(R__HAS_PTHREAD)
83 # define R__HAS_PTHREAD
84 #endif
85 #if defined(R__WIN32)
86 # define R__HAS_DECLSPEC_THREAD
87 #endif
88 
89 #if __cplusplus >= 201103L
90 
91 // Clang 3.4 also support SD-6 (feature test macros __cpp_*), but no thread local macro
92 # if defined(__clang__)
93 
94 # if __has_feature(cxx_thread_local)
95  // thread_local was added in Clang 3.3
96  // Still requires libstdc++ from GCC 4.8
97  // For that __GLIBCXX__ isn't good enough
98  // Also the MacOS build of clang does *not* support thread local yet.
99 # define R__HAS_THREAD_LOCAL
100 # else
101 # define R__HAS___THREAD
102 # endif
103 
104 # elif defined(__INTEL_COMPILER)
105 # define R__HAS__THREAD
106 
107 # elif defined(__GNUG__) && (__GNUC__ <= 4 && __GNUC_MINOR__ < 8)
108  // The C++11 thread_local keyword is supported in GCC only since 4.8
109 # define R__HAS___THREAD
110 # else
111 # define R__HAS_THREAD_LOCAL
112 # endif
113 
114 #endif
115 
116 
117 #ifdef __cplusplus
118 
119 // Note that the order is relevant, more than one of the flag might be
120 // on at the same time and we want to use 'best' option available.
121 
122 #ifdef __CINT__
123 
124 # define TTHREAD_TLS(type) static type
125 # define TTHREAD_TLS_ARRAY(type,size,name) static type name[size]
126 # define TTHREAD_TLS_PTR(name) &name
127 
128 #elif defined(R__HAS_THREAD_LOCAL)
129 
130 # define TTHREAD_TLS(type) thread_local type
131 # define TTHREAD_TLS_ARRAY(type,size,name) thread_local type name[size]
132 # define TTHREAD_TLS_PTR(name) &name
133 
134 # define TTHREAD_TLS_DECL(type, name) thread_local type name
135 # define TTHREAD_TLS_DECL_ARG(type, name, arg) thread_local type name(arg)
136 # define TTHREAD_TLS_DECL_ARG2(type, name, arg1, arg2) thread_local type name(arg1,arg2)
137 
138 #elif defined(R__HAS___THREAD)
139 
140 # define TTHREAD_TLS(type) static __thread type
141 # define TTHREAD_TLS_ARRAY(type,size,name) static __thread type name[size]
142 # define TTHREAD_TLS_PTR(name) &name
143 
144 #elif defined(R__HAS_DECLSPEC_THREAD)
145 
146 # define TTHREAD_TLS(type) static __declspec(thread) type
147 # define TTHREAD_TLS_ARRAY(type,size,name) static __declspec(thread) type name[size]
148 # define TTHREAD_TLS_PTR(name) &name
149 
150 #elif defined(R__HAS_PTHREAD)
151 
152 #include <assert.h>
153 #include <pthread.h>
154 
155 template <typename type> class TThreadTLSWrapper
156 {
157 private:
158  pthread_key_t fKey;
159  type fInitValue;
160 
161  static void key_delete(void *arg) {
162  assert (NULL != arg);
163  delete (type*)(arg);
164  }
165 
166 public:
167 
168  TThreadTLSWrapper() : fInitValue() {
169 
170  pthread_key_create(&(fKey), key_delete);
171  }
172 
173  TThreadTLSWrapper(const type &value) : fInitValue(value) {
174 
175  pthread_key_create(&(fKey), key_delete);
176  }
177 
178  ~TThreadTLSWrapper() {
179  pthread_key_delete(fKey);
180  }
181 
182  type& get() {
183  void *ptr = pthread_getspecific(fKey);
184  if (!ptr) {
185  ptr = new type(fInitValue);
186  assert (NULL != ptr);
187  (void) pthread_setspecific(fKey, ptr);
188  }
189  return *(type*)ptr;
190  }
191 
192  type& operator=(const type &in) {
193  type &ptr = get();
194  ptr = in;
195  return ptr;
196  }
197 
198  operator type&() {
199  return get();
200  }
201 
202 };
203 
204 template <typename type,int size> class TThreadTLSArrayWrapper
205 {
206 private:
207  pthread_key_t fKey;
208 
209  static void key_delete(void *arg) {
210  assert (NULL != arg);
211  delete [] (type*)(arg);
212  }
213 
214 public:
215 
216  TThreadTLSArrayWrapper() {
217 
218  pthread_key_create(&(fKey), key_delete);
219  }
220 
221  ~TThreadTLSArrayWrapper() {
222  pthread_key_delete(fKey);
223  }
224 
225  type* get() {
226  void *ptr = pthread_getspecific(fKey);
227  if (!ptr) {
228  ptr = new type[size];
229  assert (NULL != ptr);
230  (void) pthread_setspecific(fKey, ptr);
231  }
232  return (type*)ptr;
233  }
234 
235 // type& operator=(const type &in) {
236 // type &ptr = get();
237 // ptr = in;
238 // return ptr;
239 // }
240 //
241  operator type*() {
242  return get();
243  }
244 
245 };
246 
247 # define TTHREAD_TLS(type) static TThreadTLSWrapper<type>
248 # define TTHREAD_TLS_ARRAY(type,size,name) static TThreadTLSArrayWrapper<type,size> name;
249 # define TTHREAD_TLS_PTR(name) &(name.get())
250 # define TTHREAD_TLS_OBJ(index,type,name) type &name( TTHREAD_TLS_INIT<index,type>() )
251 
252 #else
253 
254 #error "No Thread Local Storage (TLS) technology for this platform specified."
255 
256 #endif
257 
258 // Available on all platforms
259 
260 
261 // Neither TTHREAD_TLS_DECL_IMPL and TTHREAD_TLS_INIT
262 // do not delete the object at the end of the process.
263 
264 #define TTHREAD_TLS_DECL_IMPL(type, name, ptr, arg) \
265  TTHREAD_TLS(type *) ptr = 0; \
266  if (!ptr) ptr = new type(arg); \
267  type &name = *ptr;
268 
269 #define TTHREAD_TLS_DECL_IMPL2(type, name, ptr, arg1, arg2) \
270  TTHREAD_TLS(type *) ptr = 0; \
271  if (!ptr) ptr = new type(arg1,arg2); \
272  type &name = *ptr;
273 
274 #ifndef TTHREAD_TLS_DECL
275 
276 #define TTHREAD_TLS_DECL(type, name) \
277  TTHREAD_TLS_DECL_IMPL(type,name,_R__JOIN_(ptr,__LINE__),)
278 
279 #define TTHREAD_TLS_DECL_ARG(type, name, arg) \
280  TTHREAD_TLS_DECL_IMPL(type,name,_R__JOIN_(ptr,__LINE__),arg)
281 
282 #define TTHREAD_TLS_DECL_ARG2(type, name, arg1, arg2) \
283  TTHREAD_TLS_DECL_IMPL2(type,name,_R__JOIN_(ptr,__LINE__),arg1,arg2)
284 
285 #endif
286 
287 template <int marker, typename T>
288 T &TTHREAD_TLS_INIT() {
289  TTHREAD_TLS(T*) ptr = NULL;
290  TTHREAD_TLS(Bool_t) isInit(kFALSE);
291  if (!isInit) {
292  ptr = new T;
293  isInit = kTRUE;
294  }
295  return *ptr;
296 }
297 
298 template <int marker, typename Array, typename T>
299 Array &TTHREAD_TLS_INIT_ARRAY() {
300  TTHREAD_TLS(Array*) ptr = NULL;
301  TTHREAD_TLS(Bool_t) isInit(kFALSE);
302  if (!isInit) {
303  ptr = new Array[sizeof(Array)/sizeof(T)];
304  isInit = kTRUE;
305  }
306  return *ptr;
307 }
308 
309 template <int marker, typename T, typename ArgType>
310 T &TTHREAD_TLS_INIT(ArgType arg) {
311  TTHREAD_TLS(T*) ptr = NULL;
312  TTHREAD_TLS(Bool_t) isInit(kFALSE);
313  if (!isInit) {
314  ptr = new T(arg);
315  isInit = kTRUE;
316  }
317  return *ptr;
318 }
319 
320 #else // __cplusplus
321 
322 #if defined(R__HAS_THREAD_LOCAL)
323 
324 # define TTHREAD_TLS_DECLARE(type,name)
325 # define TTHREAD_TLS_INIT(type,name,value) thread_local type name = (value)
326 # define TTHREAD_TLS_SET(type,name,value) name = (value)
327 # define TTHREAD_TLS_GET(type,name) (name)
328 # define TTHREAD_TLS_FREE(name)
329 
330 #elif defined(R__HAS___THREAD)
331 
332 # define TTHREAD_TLS_DECLARE(type,name)
333 # define TTHREAD_TLS_INIT(type,name,value) static __thread type name = (value)
334 # define TTHREAD_TLS_SET(type,name,value) name = (value)
335 # define TTHREAD_TLS_GET(type,name) (name)
336 # define TTHREAD_TLS_FREE(name)
337 
338 #elif defined(R__HAS_DECLSPEC_THREAD)
339 
340 # define TTHREAD_TLS_DECLARE(type,name)
341 # define TTHREAD_TLS_INIT(type,name,value) static __declspec(thread) type name = (value)
342 # define TTHREAD_TLS_SET(type,name,value) name = (value)
343 # define TTHREAD_TLS_GET(type,name) (name)
344 # define TTHREAD_TLS_FREE(name)
345 
346 #elif defined(R__HAS_PTHREAD)
347 
348 #include <assert.h>
349 #include <pthread.h>
350 
351 # define TTHREAD_TLS_DECLARE(type,name) \
352  static pthread_key_t _##name##_key; \
353  static void _##name##_key_delete(void * arg) \
354  { \
355  assert (NULL != arg); \
356  free(arg); \
357  } \
358  static void _##name##_key_create(void) \
359  { \
360  int _ret; \
361  _ret = pthread_key_create(&(_##name##_key), _##name##_key_delete); \
362  _ret = _ret; /* To get rid of warnings in case of NDEBUG */ \
363  assert (0 == _ret); \
364  } \
365  static pthread_once_t _##name##_once = PTHREAD_ONCE_INIT;
366 
367 # define TTHREAD_TLS_INIT(type,name,value) \
368  do { \
369  void *_ptr; \
370  (void) pthread_once(&(_##name##_once), _##name##_key_create); \
371  if ((_ptr = pthread_getspecific(_##name##_key)) == NULL) { \
372  _ptr = malloc(sizeof(type)); \
373  assert (NULL != _ptr); \
374  (void) pthread_setspecific(_##name##_key, _ptr); \
375  *((type*)_ptr) = (value); \
376  } \
377  } while (0)
378 
379 # define TTHREAD_TLS_SET(type,name,value) \
380  do { \
381  void *_ptr = pthread_getspecific(_##name##_key); \
382  assert (NULL != _ptr); \
383  *((type*)_ptr) = (value); \
384  } while (0)
385 
386 # define TTHREAD_TLS_GET(type,name) \
387  *((type*)pthread_getspecific(_##name##_key))
388 
389 # define TTHREAD_TLS_FREE(name) \
390  pthread_key_delete(_##name##_key);
391 
392 #else
393 
394 #error "No Thread Local Storage (TLS) technology for this platform specified."
395 
396 #endif
397 
398 #endif // __cplusplus
399 
400 #endif
401 
double T(double x)
Definition: ChebyshevPol.h:34
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kFALSE
Definition: Rtypes.h:92
const char * Array
int type
Definition: TGX11.cxx:120
typedef void((*Func_t)())
#define NULL
Definition: Rtypes.h:82
const Bool_t kTRUE
Definition: Rtypes.h:91