| // 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_ |