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   	 
40   	#ifndef ROOT_ThreadLocalStorage
41   	#define ROOT_ThreadLocalStorage
42   	
43   	#ifndef ROOT_RConfig
44   	#include "RConfig.h"
45   	#endif
46   	
47   	#ifndef ROOT_RConfigure
48   	#include "RConfigure.h"
49   	#endif
50   	
51   	#if defined(R__MACOSX)
52   	#  if defined(__clang__) && defined(MAC_OS_X_VERSION_10_7) && (defined(__x86_64__) || defined(__i386__))
53   	#    define R__HAS___THREAD
54   	#  elif !defined(R__HAS_PTHREAD)
55   	#    define R__HAS_PTHREAD
56   	#  endif
57   	#endif
58   	#if defined(R__LINUX) || defined(R__AIX)
59   	#  define R__HAS___THREAD
60   	#endif
61   	#if defined(R__SOLARIS) && !defined(R__HAS_PTHREAD)
62   	#  define R__HAS_PTHREAD
63   	#endif
64   	#if defined(R__WIN32)
65   	#  define R__HAS_DECLSPEC_THREAD
66   	#endif
67   	
68   	#if __cplusplus >= 201103L
69   	
70   	// Note: it would be tempting to use __has_feature(cxx_thread_local) but despite
71   	// documentation claims it support for it ... it is in fact ineffective (return
72   	// a false negative).
73   	// Clang 3.4 also support SD-6 (feature test macros __cpp_*), but no thread local macro
74   	#  if defined(__clang__) && (__clang_major__ >= 3 && __clang_minor__ >= 3)
75   	     // thread_local was added in Clang 3.3
76   	     // Still requires libstdc++ from GCC 4.8
77   	     // For that __GLIBCXX__ isn't good enough
78   	#    define R__HAS_THREAD_LOCAL
79   	
80   	#  elif defined(__GNUG__) && (__GNUC__ <= 4 && __GNUC_MINOR__ < 80)
81   	    // The C++11 thread_local keyword is supported in GCC only since 4.8
82   	#    define R__HAS___THREAD
83   	#  else
84   	#    define R__HAS_THREAD_LOCAL
85   	#  endif
86   	
87   	#endif
88   	
89   	
90   	#ifdef __cplusplus
91   	
92   	// Note that the order is relevant, more than one of the flag might be
93   	// on at the same time and we want to use 'best' option available.
94   	
95   	#ifdef __CINT__
96   	
97   	#  define TTHREAD_TLS(type) static type
98   	#  define TTHREAD_TLS_ARRAY(type,size,name) static type name[size];
99   	#  define TTHREAD_TLS_PTR(name) &name
100  	
101  	#elif defined(R__HAS_THREAD_LOCAL)
102  	
103  	#  define TTHREAD_TLS(type) thread_local type
104  	#  define TTHREAD_TLS_ARRAY(type,size,name) thread_local type name[size];
105  	#  define TTHREAD_TLS_PTR(name) &name
106  	
107  	#elif defined(R__HAS___THREAD)
108  	
109  	#  define TTHREAD_TLS(type)  static __thread type
110  	#  define TTHREAD_TLS_ARRAY(type,size,name) static __thread type name[size];
111  	#  define TTHREAD_TLS_PTR(name) &name
112  	
113  	#elif defined(R__HAS_DECLSPEC_THREAD)
114  	
115  	#  define TTHREAD_TLS(type) static __declspec(thread) type
116  	#  define TTHREAD_TLS_ARRAY(type,size,name) static __declspec(thread) type name[size];
117  	#  define TTHREAD_TLS_PTR(name) &name
118  	
119  	#elif defined(R__HAS_PTHREAD)
120  	
121  	#include <assert.h>
122  	#include <pthread.h>
123  	
124  	template <typename type> class TThreadTLSWrapper
125  	{
126  	private:
127  	   pthread_key_t  fKey;
128  	   type           fInitValue;
129  	   
130  	   static void key_delete(void *arg) {
131  	      assert (NULL != arg);
132  	      delete (type*)(arg);
133  	   }
134  	
135  	public:
136  	
137  	   TThreadTLSWrapper() : fInitValue() {
138  	
139  	      pthread_key_create(&(fKey), key_delete);
140  	   }
141  	
142  	   TThreadTLSWrapper(const type &value) : fInitValue(value) {
143  	
144  	      pthread_key_create(&(fKey), key_delete);
145  	   }
146  	
147  	   ~TThreadTLSWrapper() {
148  	      pthread_key_delete(fKey);
149  	   }
150  	
151  	   type& get() {
152  	      void *ptr = pthread_getspecific(fKey);
153  	      if (!ptr) {
154  	         ptr = new type(fInitValue);
155  	         assert (NULL != ptr);
156  	         (void) pthread_setspecific(fKey, ptr);
157  	      }
158  	      return *(type*)ptr;
159  	   }
160  	
161  	   type& operator=(const type &in) {
162  	      type &ptr = get();
163  	      ptr = in;
164  	      return ptr;
165  	   }
166  	
167  	   operator type&() {
168  	      return get();
169  	   }
170  	
171  	};
172  	
173  	template <typename type,int size> class TThreadTLSArrayWrapper
174  	{
175  	private:
176  	   pthread_key_t  fKey;
177  	
178  	   static void key_delete(void *arg) {
179  	      assert (NULL != arg);
180  	      delete [] (type*)(arg);
181  	   }
182  	
183  	public:
184  	
185  	   TThreadTLSArrayWrapper() {
186  	
187  	      pthread_key_create(&(fKey), key_delete);
188  	   }
189  	
190  	   ~TThreadTLSArrayWrapper() {
191  	      pthread_key_delete(fKey);
192  	   }
193  	
194  	   type* get() {
195  	      void *ptr = pthread_getspecific(fKey);
196  	      if (!ptr) {
197  	         ptr = new type[size];
198  	         assert (NULL != ptr);
199  	         (void) pthread_setspecific(fKey, ptr);
200  	      }
201  	      return  (type*)ptr;
202  	   }
203  	
204  	//   type& operator=(const type &in) {
205  	//      type &ptr = get();
206  	//      ptr = in;
207  	//      return ptr;
208  	//   }
209  	//
210  	   operator type*() {
211  	      return get();
212  	   }
213  	   
214  	};
215  	
216  	#  define TTHREAD_TLS(type) static TThreadTLSWrapper<type>
217  	#  define TTHREAD_TLS_ARRAY(type,size,name) static TThreadTLSArrayWrapper<type,size> name;
218  	#  define TTHREAD_TLS_PTR(name) &(name.get())
219  	#else
220  	
221  	#error "No Thread Local Storage (TLS) technology for this platform specified."
222  	
223  	#endif
224  	
225  	// Available on all platforms
226  	template <int marker, typename T>
227  	T &TTHREAD_TLS_INIT() {
228  	   TTHREAD_TLS(T*) ptr = NULL;
229  	   TTHREAD_TLS(Bool_t) isInit(kFALSE);
230  	   if (!isInit) {
231  	      ptr = new T;
232  	      isInit = kTRUE;
233  	   }
234  	   return *ptr;
235  	}
236  	
237  	template <int marker, typename Array, typename T>
238  	Array &TTHREAD_TLS_INIT_ARRAY() {
239  	   TTHREAD_TLS(Array*) ptr = NULL;
240  	   TTHREAD_TLS(Bool_t) isInit(kFALSE);
241  	   if (!isInit) {
242  	      ptr = new Array[sizeof(Array)/sizeof(T)];
243  	      isInit = kTRUE;
244  	   }
245  	   return *ptr;
246  	}
247  	
248  	template <int marker, typename T, typename ArgType>
249  	T &TTHREAD_TLS_INIT(ArgType arg) {
250  	   TTHREAD_TLS(T*) ptr = NULL;
251  	   TTHREAD_TLS(Bool_t) isInit(kFALSE);
252  	   if (!isInit) {
253  	      ptr = new T(arg);
254  	      isInit = kTRUE;
255  	   }
256  	   return *ptr;
257  	}
258  	
259  	#else // __cplusplus
260  	
261  	#if defined(R__HAS_THREAD_LOCAL)
262  	
263  	#  define TTHREAD_TLS_DECLARE(type,name)
264  	#  define TTHREAD_TLS_INIT(type,name,value) thread_local type name = (value)
265  	#  define TTHREAD_TLS_SET(type,name,value)  name = (value)
266  	#  define TTHREAD_TLS_GET(type,name)        (name)
267  	#  define TTHREAD_TLS_FREE(name)
268  	
269  	#elif defined(R__HAS___THREAD)
270  	
271  	#  define TTHREAD_TLS_DECLARE(type,name)
272  	#  define TTHREAD_TLS_INIT(type,name,value) static __thread type name = (value)
273  	#  define TTHREAD_TLS_SET(type,name,value)  name = (value)
274  	#  define TTHREAD_TLS_GET(type,name)        (name)
275  	#  define TTHREAD_TLS_FREE(name)
276  	
277  	#elif defined(R__HAS_DECLSPEC_THREAD)
278  	
279  	#  define TTHREAD_TLS_DECLARE(type,name)
280  	#  define TTHREAD_TLS_INIT(type,name,value) static __declspec(thread) type name = (value)
281  	#  define TTHREAD_TLS_SET(type,name,value)  name = (value)
282  	#  define TTHREAD_TLS_GET(type,name)        (name)
283  	#  define TTHREAD_TLS_FREE(name)
284  	
285  	#elif defined(R__HAS_PTHREAD)
286  	
287  	#include <assert.h>
288  	#include <pthread.h>
289  	
290  	#  define TTHREAD_TLS_DECLARE(type,name)                                     \
291  	   static pthread_key_t _##name##_key;                                       \
292  	   static void _##name##_key_delete(void * arg)                              \
293  	   {                                                                         \
294  	     assert (NULL != arg);                                                   \
295  	     free(arg);                                                              \
296  	   }                                                                         \
297  	   static void _##name##_key_create(void)                                    \
298  	   {                                                                         \
299  	     int _ret;                                                               \
300  	     _ret = pthread_key_create(&(_##name##_key), _##name##_key_delete);      \
301  	     _ret = _ret; /* To get rid of warnings in case of NDEBUG */             \
302  	     assert (0 == _ret);                                                     \
303  	   }                                                                         \
304  	   static pthread_once_t _##name##_once = PTHREAD_ONCE_INIT;
305  	
306  	#  define TTHREAD_TLS_INIT(type,name,value)                                  \
307  	   do {                                                                      \
308  	     void *_ptr;                                                             \
309  	     (void) pthread_once(&(_##name##_once), _##name##_key_create);           \
310  	     if ((_ptr = pthread_getspecific(_##name##_key)) == NULL) {              \
311  	       _ptr = malloc(sizeof(type));                                          \
312  	       assert (NULL != _ptr);                                                \
313  	       (void) pthread_setspecific(_##name##_key, _ptr);                      \
314  	       *((type*)_ptr) = (value);                                             \
315  	     }                                                                       \
316  	   } while (0)
317  	
318  	#  define TTHREAD_TLS_SET(type,name,value)                                   \
319  	   do {                                                                      \
320  	     void *_ptr = pthread_getspecific(_##name##_key);                        \
321  	     assert (NULL != _ptr);                                                  \
322  	     *((type*)_ptr) = (value);                                               \
323  	   } while (0)
324  	
325  	#  define TTHREAD_TLS_GET(type,name)                                         \
326  	     *((type*)pthread_getspecific(_##name##_key))
327  	
328  	#  define TTHREAD_TLS_FREE(name)                                             \
329  	     pthread_key_delete(_##name##_key);
330  	
331  	#else
332  	
333  	#error "No Thread Local Storage (TLS) technology for this platform specified."
334  	
335  	#endif
336  	
337  	#endif // __cplusplus
338  	
339  	#endif
340  	
341