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