1 // 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
42 #ifdef __linux__
43
44 #define DEFINE_THREAD_LOCAL(Type, name) thread_local Type name
45 #define TLS_REF(x) x
46
47 #else
48
49 // 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.
53 template <typename Type>
ThreadLocalDestructor(void * ptr)54 void ThreadLocalDestructor(void* ptr) {
55 delete reinterpret_cast<Type>(ptr);
56 }
57
58 template<typename Type, pthread_key_t* key>
ThreadLocalInit()59 void ThreadLocalInit() {
60 if (pthread_key_create(key, ThreadLocalDestructor<Type>))
61 ERROR("Failed to create a pthread key for TLS errno=%d", errno);
62 }
63
64 template<typename Type, pthread_key_t* key, pthread_once_t* once>
65 class ThreadLocal {
66 public:
Ref()67 Type& Ref() {
68 return *GetPointer();
69 }
Get()70 Type Get() {
71 return Ref();
72 }
Set(const Type & value)73 void Set(const Type& value) {
74 Ref() = value;
75 }
GetPointer()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
98 #define TLS_REF(x) x.Ref()
99
100 #endif
101
102 #endif // THREAD_LOCAL_H_
103