102 lines
2.9 KiB
C++
102 lines
2.9 KiB
C++
// 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_
|