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() { return *GetPointer(); }
Get()68 Type Get() { return Ref(); }
Set(const Type & value)69 void Set(const Type& value) { Ref() = value; }
GetPointer()70 Type* GetPointer() {
71 pthread_once(once, ThreadLocalInit<Type*, key>);
72 Type* value = reinterpret_cast<Type*>(pthread_getspecific(*key));
73 if (value)
74 return value;
75 // new Type() for PODs means zero initialization.
76 value = new Type();
77 int error = pthread_setspecific(*key, value);
78 if (error != 0)
79 ERROR("Failed to set a TLS: error=%d", error);
80 return value;
81 }
82 };
83
84 // We need a namespace for name##_key and name##_once since template parameters
85 // do not accept unnamed values such as static global variables.
86 #define DEFINE_THREAD_LOCAL(Type, name) \
87 namespace { \
88 pthread_once_t name##_once = PTHREAD_ONCE_INIT; \
89 pthread_key_t name##_key; \
90 } \
91 ThreadLocal<Type, &name##_key, &name##_once> name;
92
93 #define TLS_REF(x) x.Ref()
94
95 #endif
96
97 #endif // THREAD_LOCAL_H_
98