| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| // A simple cross platform thread local storage implementation. |
| // |
| // This is a drop-in replacement of __thread keyword. If your compiler |
| // toolchain supports __thread keyword, the user of this code should |
| // be as fast as the code which uses __thread. Chrome's |
| // base::ThreadLocalPointer and base::ThreadLocalStorage cannot be as |
| // fast as __thread. |
| // TODO(crbug.com/249345): If pthread_getspecific is slow for our use, |
| // expose bionic's internal TLS and stop using pthread_getspecific |
| // based implementation. |
| // |
| // Usage: |
| // |
| // Before (linux): |
| // |
| // __thread Foo* foo; |
| // foo = new Foo(); |
| // foo->func(); |
| // |
| // |
| // After: |
| // |
| // DEFINE_THREAD_LOCAL(Foo*, foo); |
| // foo.Ref() = new Foo(); |
| // foo.Ref()->func(); |
| // |
| // Thread local PODs are zero-initialized. |
| // Thread local non-PODs are initialized with the default constructor. |
| |
| #ifndef THREAD_LOCAL_H_ |
| #define THREAD_LOCAL_H_ |
| |
| #include <errno.h> |
| #include <pthread.h> |
| |
| #include "log.h" |
| |
| #ifdef __linux__ |
| |
| #define DEFINE_THREAD_LOCAL(Type, name) thread_local Type name |
| #define TLS_REF(x) x |
| |
| #else |
| |
| // Thread local storage implementation which uses pthread. |
| // Note that DEFINE_THREAD_LOCAL creates a global variable just like |
| // thread local storage based on __thread keyword. So we should not use |
| // constructor in ThreadLocal class to avoid static initializator. |
| template <typename Type> |
| void ThreadLocalDestructor(void* ptr) { |
| delete reinterpret_cast<Type>(ptr); |
| } |
| |
| template<typename Type, pthread_key_t* key> |
| void ThreadLocalInit() { |
| if (pthread_key_create(key, ThreadLocalDestructor<Type>)) |
| ERROR("Failed to create a pthread key for TLS errno=%d", errno); |
| } |
| |
| template<typename Type, pthread_key_t* key, pthread_once_t* once> |
| class ThreadLocal { |
| public: |
| Type& Ref() { |
| return *GetPointer(); |
| } |
| Type Get() { |
| return Ref(); |
| } |
| void Set(const Type& value) { |
| Ref() = value; |
| } |
| Type* GetPointer() { |
| pthread_once(once, ThreadLocalInit<Type*, key>); |
| Type* value = reinterpret_cast<Type*>(pthread_getspecific(*key)); |
| if (value) return value; |
| // new Type() for PODs means zero initialization. |
| value = new Type(); |
| int error = pthread_setspecific(*key, value); |
| if (error != 0) |
| ERROR("Failed to set a TLS: error=%d", error); |
| return value; |
| } |
| }; |
| |
| // We need a namespace for name##_key and name##_once since template parameters |
| // do not accept unnamed values such as static global variables. |
| #define DEFINE_THREAD_LOCAL(Type, name) \ |
| namespace { \ |
| pthread_once_t name##_once = PTHREAD_ONCE_INIT; \ |
| pthread_key_t name##_key; \ |
| } \ |
| ThreadLocal<Type, &name##_key, &name##_once> name; |
| |
| #define TLS_REF(x) x.Ref() |
| |
| #endif |
| |
| #endif // THREAD_LOCAL_H_ |