• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // tls.cpp: Simple cross-platform interface for thread local storage.
8 
9 #include "common/tls.h"
10 
11 #include "common/debug.h"
12 
13 #ifdef ANGLE_ENABLE_WINDOWS_UWP
14 #    include <map>
15 #    include <mutex>
16 #    include <set>
17 #    include <vector>
18 
19 #    include <Windows.System.Threading.h>
20 #    include <wrl/async.h>
21 #    include <wrl/client.h>
22 
23 using namespace std;
24 using namespace Windows::Foundation;
25 using namespace ABI::Windows::System::Threading;
26 
27 // Thread local storage for Windows Store support
28 typedef vector<void *> ThreadLocalData;
29 
30 static __declspec(thread) ThreadLocalData *currentThreadData = nullptr;
31 static set<ThreadLocalData *> allThreadData;
32 static DWORD nextTlsIndex = 0;
33 static vector<DWORD> freeTlsIndices;
34 
35 #endif
36 
37 bool gUseAndroidOpenGLTlsSlot = false;
38 
CreateTLSIndex(PthreadKeyDestructor destructor)39 TLSIndex CreateTLSIndex(PthreadKeyDestructor destructor)
40 {
41     TLSIndex index;
42 
43 #ifdef ANGLE_PLATFORM_WINDOWS
44 #    ifdef ANGLE_ENABLE_WINDOWS_UWP
45     if (!freeTlsIndices.empty())
46     {
47         DWORD result = freeTlsIndices.back();
48         freeTlsIndices.pop_back();
49         index = result;
50     }
51     else
52     {
53         index = nextTlsIndex++;
54     }
55 #    else
56     index = TlsAlloc();
57 #    endif
58 
59 #elif defined(ANGLE_PLATFORM_POSIX)
60     // Create pthread key
61     if ((pthread_key_create(&index, destructor)) != 0)
62     {
63         index = TLS_INVALID_INDEX;
64     }
65 #endif
66 
67     ASSERT(index != TLS_INVALID_INDEX && "CreateTLSIndex: Unable to allocate Thread Local Storage");
68     return index;
69 }
70 
DestroyTLSIndex(TLSIndex index)71 bool DestroyTLSIndex(TLSIndex index)
72 {
73     ASSERT(index != TLS_INVALID_INDEX && "DestroyTLSIndex(): Invalid TLS Index");
74     if (index == TLS_INVALID_INDEX)
75     {
76         return false;
77     }
78 
79 #ifdef ANGLE_PLATFORM_WINDOWS
80 #    ifdef ANGLE_ENABLE_WINDOWS_UWP
81     ASSERT(index < nextTlsIndex);
82     ASSERT(find(freeTlsIndices.begin(), freeTlsIndices.end(), index) == freeTlsIndices.end());
83 
84     freeTlsIndices.push_back(index);
85     for (auto threadData : allThreadData)
86     {
87         if (threadData->size() > index)
88         {
89             threadData->at(index) = nullptr;
90         }
91     }
92     return true;
93 #    else
94     return (TlsFree(index) == TRUE);
95 #    endif
96 #elif defined(ANGLE_PLATFORM_POSIX)
97     return (pthread_key_delete(index) == 0);
98 #endif
99 }
100 
SetTLSValue(TLSIndex index,void * value)101 bool SetTLSValue(TLSIndex index, void *value)
102 {
103     ASSERT(index != TLS_INVALID_INDEX && "SetTLSValue(): Invalid TLS Index");
104     if (index == TLS_INVALID_INDEX)
105     {
106         return false;
107     }
108 
109 #ifdef ANGLE_PLATFORM_WINDOWS
110 #    ifdef ANGLE_ENABLE_WINDOWS_UWP
111     ThreadLocalData *threadData = currentThreadData;
112     if (!threadData)
113     {
114         threadData = new ThreadLocalData(index + 1, nullptr);
115         allThreadData.insert(threadData);
116         currentThreadData = threadData;
117     }
118     else if (threadData->size() <= index)
119     {
120         threadData->resize(index + 1, nullptr);
121     }
122 
123     threadData->at(index) = value;
124     return true;
125 #    else
126     return (TlsSetValue(index, value) == TRUE);
127 #    endif
128 #elif defined(ANGLE_PLATFORM_POSIX)
129     return (pthread_setspecific(index, value) == 0);
130 #endif
131 }
132 
GetTLSValue(TLSIndex index)133 void *GetTLSValue(TLSIndex index)
134 {
135     ASSERT(index != TLS_INVALID_INDEX && "GetTLSValue(): Invalid TLS Index");
136     if (index == TLS_INVALID_INDEX)
137     {
138         return nullptr;
139     }
140 
141 #ifdef ANGLE_PLATFORM_WINDOWS
142 #    ifdef ANGLE_ENABLE_WINDOWS_UWP
143     ThreadLocalData *threadData = currentThreadData;
144     if (threadData && threadData->size() > index)
145     {
146         return threadData->at(index);
147     }
148     else
149     {
150         return nullptr;
151     }
152 #    else
153     return TlsGetValue(index);
154 #    endif
155 #elif defined(ANGLE_PLATFORM_POSIX)
156     return pthread_getspecific(index);
157 #endif
158 }
159