blob: 28b146a7e150a1a9c31146bc17877e7988058841 [file] [log] [blame]
Shinichiro Hamaji4197da62016-01-25 16:06:29 +09001// 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
Shinichiro Hamaji545b6a22016-02-15 18:43:47 +090042#ifdef __linux__
43
44#define DEFINE_THREAD_LOCAL(Type, name) thread_local Type name
45#define TLS_REF(x) x
46
47#else
48
Shinichiro Hamaji4197da62016-01-25 16:06:29 +090049// 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.
53template <typename Type>
54void ThreadLocalDestructor(void* ptr) {
55 delete reinterpret_cast<Type>(ptr);
56}
57
58template<typename Type, pthread_key_t* key>
59void ThreadLocalInit() {
60 if (pthread_key_create(key, ThreadLocalDestructor<Type>))
61 ERROR("Failed to create a pthread key for TLS errno=%d", errno);
62}
63
64template<typename Type, pthread_key_t* key, pthread_once_t* once>
65class 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
Shinichiro Hamaji545b6a22016-02-15 18:43:47 +090098#define TLS_REF(x) x.Ref()
99
100#endif
101
Shinichiro Hamaji4197da62016-01-25 16:06:29 +0900102#endif // THREAD_LOCAL_H_