1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 // 5 // A simple cross platform thread local storage implementation. 6 // 7 // This is a drop-in replacement of __thread keyword. If your compiler 8 // toolchain supports __thread keyword, the user of this code should 9 // be as fast as the code which uses __thread. Chrome's 10 // base::ThreadLocalPointer and base::ThreadLocalStorage cannot be as 11 // fast as __thread. 12 // TODO(crbug.com/249345): If pthread_getspecific is slow for our use, 13 // expose bionic's internal TLS and stop using pthread_getspecific 14 // based implementation. 15 // 16 // Usage: 17 // 18 // Before (linux): 19 // 20 // __thread Foo* foo; 21 // foo = new Foo(); 22 // foo->func(); 23 // 24 // 25 // After: 26 // 27 // DEFINE_THREAD_LOCAL(Foo*, foo); 28 // foo.Ref() = new Foo(); 29 // foo.Ref()->func(); 30 // 31 // Thread local PODs are zero-initialized. 32 // Thread local non-PODs are initialized with the default constructor. 33 34 #ifndef THREAD_LOCAL_H_ 35 #define THREAD_LOCAL_H_ 36 37 #include <errno.h> 38 #include <pthread.h> 39 40 #include "log.h" 41 42 #ifdef __linux__ 43 44 #define DEFINE_THREAD_LOCAL(Type, name) thread_local Type name 45 #define TLS_REF(x) x 46 47 #else 48 49 // Thread local storage implementation which uses pthread. 50 // Note that DEFINE_THREAD_LOCAL creates a global variable just like 51 // thread local storage based on __thread keyword. So we should not use 52 // constructor in ThreadLocal class to avoid static initializator. 53 template <typename Type> 54 void ThreadLocalDestructor(void* ptr) { 55 delete reinterpret_cast<Type>(ptr); 56 } 57 58 template<typename Type, pthread_key_t* key> 59 void ThreadLocalInit() { 60 if (pthread_key_create(key, ThreadLocalDestructor<Type>)) 61 ERROR("Failed to create a pthread key for TLS errno=%d", errno); 62 } 63 64 template<typename Type, pthread_key_t* key, pthread_once_t* once> 65 class ThreadLocal { 66 public: 67 Type& Ref() { 68 return *GetPointer(); 69 } 70 Type Get() { 71 return Ref(); 72 } 73 void Set(const Type& value) { 74 Ref() = value; 75 } 76 Type* GetPointer() { 77 pthread_once(once, ThreadLocalInit<Type*, key>); 78 Type* value = reinterpret_cast<Type*>(pthread_getspecific(*key)); 79 if (value) return value; 80 // new Type() for PODs means zero initialization. 81 value = new Type(); 82 int error = pthread_setspecific(*key, value); 83 if (error != 0) 84 ERROR("Failed to set a TLS: error=%d", error); 85 return value; 86 } 87 }; 88 89 // We need a namespace for name##_key and name##_once since template parameters 90 // do not accept unnamed values such as static global variables. 91 #define DEFINE_THREAD_LOCAL(Type, name) \ 92 namespace { \ 93 pthread_once_t name##_once = PTHREAD_ONCE_INIT; \ 94 pthread_key_t name##_key; \ 95 } \ 96 ThreadLocal<Type, &name##_key, &name##_once> name; 97 98 #define TLS_REF(x) x.Ref() 99 100 #endif 101 102 #endif // THREAD_LOCAL_H_ 103