1 // Copyright (C) 2014 The Android Open Source Project
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 #include "emugl/common/thread_store.h"
18 #include "emugl/common/lazy_instance.h"
26 // Set to 1 to print debug messages.
27 #define DEBUG_THREAD_STORE 0
29 #if DEBUG_THREAD_STORE
30 # define D(...) do { printf("%s:%d: ", __FUNCTION__, __LINE__); printf(__VA_ARGS__); fflush(stdout); } while (0)
32 # define D(...) ((void)0)
41 // The ThreadStore implementation on Windows is very tricky, because
42 // TlsAlloc() doesn't allow one to provide a destructor function. As
43 // such threads are expected to destroy all TLS values explicitely.
45 // To solve this issue, this source file provides a static method called
46 // ThreadStore::OnThreadExit() that must be called when a thread exits,
47 // which will cleanup all values for the current thread.
49 // But this forces us to track thread-specific values ourselves.
51 // Maximum amount of thread-specific slots supported by this implementation.
56 // TlsSlotArray is a thread-specific array of values. Instances will
57 // be stored in a Win32 TLS value controlled by a single master TLS
60 typedef void* TlsSlotArray[kMaxTlsSlots];
62 // Global state shared by all threads
67 mMasterTls = TlsAlloc();
68 D("Master TLS = %d\n", (int)mMasterTls);
69 InitializeCriticalSection(&mSection);
71 ::memset(mDestructors, 0, sizeof(mDestructors));
75 // Register a new TLS key, or return -1 on error (too many keys).
76 // |destroy| is the destructor function for the key.
77 int registerKey(ThreadStore::Destructor* destroy) {
78 D("Entering destroy=%p\n", destroy);
80 EnterCriticalSection(&mSection);
81 if (mLastIndex < kMaxTlsSlots) {
83 mDestructors[ret] = destroy;
85 LeaveCriticalSection(&mSection);
86 D("Exiting newKey=%d\n", ret);
90 void unregisterKey(int key) {
92 if (key < 0 || key >= kMaxTlsSlots) {
97 // Note: keys are not reusable, but remove the destructor to avoid
98 // crashes in leaveCurrentThread() when it points to a function that
99 // is going to be unloaded from the process' address space.
100 EnterCriticalSection(&mSection);
101 mDestructors[key] = NULL;
102 LeaveCriticalSection(&mSection);
106 // Get the current thread-local value for a given |key|.
107 void* getValue(int key) const {
108 D("Entering key=%d\n", key);
109 if (key < 0 || key >= kMaxTlsSlots) {
110 D("Invalid key, result=NULL\n");
114 TlsSlotArray* array = getArray();
115 void* ret = (*array)[key];
116 D("Exiting keyValue=%p\n", ret);
120 // Set the current thread-local |value| for a given |key|.
121 void setValue(int key, void* value) {
122 D("Entering key=%d\n",key);
123 if (key < 0 || key >= kMaxTlsSlots) {
124 D("Invalid key, returning\n");
128 TlsSlotArray* array = getArray();
129 (*array)[key] = value;
133 // Call this when a thread exits to destroy all its thread-local values.
134 void leaveCurrentThread() {
136 TlsSlotArray* array =
137 reinterpret_cast<TlsSlotArray*>(TlsGetValue(mMasterTls));
139 D("Exiting, no thread-local data in this thread\n");
143 for (size_t n = 0; n < kMaxTlsSlots; ++n) {
144 void* value = array[n];
147 // NOTE: In theory, a destructor could reset the slot to
148 // a new value, and we would have to loop in this function
149 // in interesting ways. In practice, ignore the issue.
150 EnterCriticalSection(&mSection);
151 ThreadStore::Destructor* destroy = mDestructors[n];
152 LeaveCriticalSection(&mSection);
154 D("Calling destructor %p for key=%d, with value=%p\n",
155 destroy, (int)n, value);
160 TlsSetValue(mMasterTls, NULL);
166 // Return the thread-local array of TLS slots for the current thread.
167 // Cannot return NULL.
168 TlsSlotArray* getArray() const {
170 TlsSlotArray* array =
171 reinterpret_cast<TlsSlotArray*>(TlsGetValue(mMasterTls));
173 array = reinterpret_cast<TlsSlotArray*>(
174 ::calloc(sizeof(*array), 1));
175 TlsSetValue(mMasterTls, array);
176 D("Allocated new array at %p\n", array);
178 D("Retrieved array at %p\n", array);
184 CRITICAL_SECTION mSection;
186 ThreadStore::Destructor* mDestructors[kMaxTlsSlots];
189 LazyInstance<GlobalState> gGlobalState = LAZY_INSTANCE_INIT;
193 ThreadStore::ThreadStore(Destructor* destroy) {
194 D("Entering this=%p destroy=%p\n", this, destroy);
195 mKey = gGlobalState->registerKey(destroy);
196 D("Exiting this=%p key=%d\n", this, mKey);
199 ThreadStore::~ThreadStore() {
200 D("Entering this=%p\n", this);
201 GlobalState* state = gGlobalState.ptr();
202 state->unregisterKey(mKey);
203 D("Exiting this=%p\n", this);
206 void* ThreadStore::get() const {
207 D("Entering this=%p\n", this);
208 void* ret = gGlobalState->getValue(mKey);
209 D("Exiting this=%p value=%p\n", this, ret);
213 void ThreadStore::set(void* value) {
214 D("Entering this=%p value=%p\n", this, value);
215 gGlobalState->setValue(mKey, value);
216 D("Exiting this=%p\n", this);
220 void ThreadStore::OnThreadExit() {
221 gGlobalState->leaveCurrentThread();
226 ThreadStore::ThreadStore(Destructor* destroy) {
227 int ret = pthread_key_create(&mKey, destroy);
230 "Could not create thread store key: %s\n",
236 ThreadStore::~ThreadStore() {
237 pthread_key_delete(mKey);