// 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 #include #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 void ThreadLocalDestructor(void* ptr) { delete reinterpret_cast(ptr); } template void ThreadLocalInit() { if (pthread_key_create(key, ThreadLocalDestructor)) ERROR("Failed to create a pthread key for TLS errno=%d", errno); } template 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* value = reinterpret_cast(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 name; #define TLS_REF(x) x.Ref() #endif #endif // THREAD_LOCAL_H_