TYPE3
[iec.git] / src / type3_AndroidCloud / anbox-master / external / android-emugl / shared / emugl / common / thread_store.cpp
1 // Copyright (C) 2014 The Android Open Source Project
2 //
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
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
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.
14
15 #include "emugl/common/thread_store.h"
16
17 #ifdef _WIN32
18 #include "emugl/common/lazy_instance.h"
19 #endif
20
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 // Set to 1 to print debug messages.
27 #define DEBUG_THREAD_STORE  0
28
29 #if DEBUG_THREAD_STORE
30 #  define D(...)   do { printf("%s:%d: ", __FUNCTION__, __LINE__); printf(__VA_ARGS__); fflush(stdout); } while (0)
31 #else
32 #  define D(...)   ((void)0)
33 #endif
34
35 namespace emugl {
36
37 #ifdef _WIN32
38
39 namespace {
40
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.
44 //
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.
48 //
49 // But this forces us to track thread-specific values ourselves.
50
51 // Maximum amount of thread-specific slots supported by this implementation.
52 enum {
53     kMaxTlsSlots = 64
54 };
55
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
58 // key.
59 //
60 typedef void* TlsSlotArray[kMaxTlsSlots];
61
62 // Global state shared by all threads
63 class GlobalState {
64 public:
65     GlobalState() {
66         D("Entering\n");
67         mMasterTls = TlsAlloc();
68         D("Master TLS = %d\n", (int)mMasterTls);
69         InitializeCriticalSection(&mSection);
70         mLastIndex = 0;
71         ::memset(mDestructors, 0, sizeof(mDestructors));
72         D("Exiting\n");
73     }
74
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);
79         int ret = -1;
80         EnterCriticalSection(&mSection);
81         if (mLastIndex < kMaxTlsSlots) {
82             ret = mLastIndex++;
83             mDestructors[ret] = destroy;
84         }
85         LeaveCriticalSection(&mSection);
86         D("Exiting newKey=%d\n", ret);
87         return ret;
88     }
89
90     void unregisterKey(int key) {
91         D("key=%d\n", key);
92         if (key < 0 || key >= kMaxTlsSlots) {
93             D("Invalid key\n");
94             return;
95         }
96
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);
103         D("Exiting\n");
104     }
105
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");
111             return NULL;
112         }
113
114         TlsSlotArray* array = getArray();
115         void* ret = (*array)[key];
116         D("Exiting keyValue=%p\n", ret);
117         return ret;
118     }
119
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");
125             return;
126         }
127
128         TlsSlotArray* array = getArray();
129         (*array)[key] = value;
130         D("Exiting\n");
131     }
132
133     // Call this when a thread exits to destroy all its thread-local values.
134     void leaveCurrentThread() {
135         D("Entering\n");
136         TlsSlotArray* array =
137                 reinterpret_cast<TlsSlotArray*>(TlsGetValue(mMasterTls));
138         if (!array) {
139             D("Exiting, no thread-local data in this thread\n");
140             return;
141         }
142
143         for (size_t n = 0; n < kMaxTlsSlots; ++n) {
144             void* value = array[n];
145             if (value) {
146                 (*array)[n] = NULL;
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);
153                 if (destroy) {
154                     D("Calling destructor %p for key=%d, with value=%p\n",
155                       destroy, (int)n, value);
156                     (*destroy)(value);
157                 }
158             }
159         }
160         TlsSetValue(mMasterTls, NULL);
161         ::free(array);
162         D("Exiting\n");
163     }
164
165 private:
166     // Return the thread-local array of TLS slots for the current thread.
167     // Cannot return NULL.
168     TlsSlotArray* getArray() const {
169         D("Entering\n");
170         TlsSlotArray* array =
171                 reinterpret_cast<TlsSlotArray*>(TlsGetValue(mMasterTls));
172         if (!array) {
173             array = reinterpret_cast<TlsSlotArray*>(
174                     ::calloc(sizeof(*array), 1));
175             TlsSetValue(mMasterTls, array);
176             D("Allocated new array at %p\n", array);
177         } else {
178             D("Retrieved array at %p\n", array);
179         }
180         return array;
181     }
182
183     DWORD mMasterTls;
184     CRITICAL_SECTION mSection;
185     int mLastIndex;
186     ThreadStore::Destructor* mDestructors[kMaxTlsSlots];
187 };
188
189 LazyInstance<GlobalState> gGlobalState = LAZY_INSTANCE_INIT;
190
191 }  // namespace
192
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);
197 }
198
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);
204 }
205
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);
210     return ret;
211 }
212
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);
217 }
218
219 // static
220 void ThreadStore::OnThreadExit() {
221     gGlobalState->leaveCurrentThread();
222 }
223
224 #else  // !_WIN32
225
226 ThreadStore::ThreadStore(Destructor* destroy) {
227     int ret = pthread_key_create(&mKey, destroy);
228     if (ret != 0) {
229         fprintf(stderr,
230                 "Could not create thread store key: %s\n",
231                 strerror(ret));
232         exit(1);
233     }
234 }
235
236 ThreadStore::~ThreadStore() {
237     pthread_key_delete(mKey);
238 }
239
240 #endif  // !_WIN32
241
242 }  // namespace emugl