• 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 namespace angle
38 {
39 
CreateTLSIndex(PthreadKeyDestructor destructor)40 TLSIndex CreateTLSIndex(PthreadKeyDestructor destructor)
41 {
42     TLSIndex index;
43 
44 #ifdef ANGLE_PLATFORM_WINDOWS
45 #    ifdef ANGLE_ENABLE_WINDOWS_UWP
46     if (!freeTlsIndices.empty())
47     {
48         DWORD result = freeTlsIndices.back();
49         freeTlsIndices.pop_back();
50         index = result;
51     }
52     else
53     {
54         index = nextTlsIndex++;
55     }
56 #    else
57     index = TlsAlloc();
58 #    endif
59 
60 #elif defined(ANGLE_PLATFORM_POSIX)
61     // Create pthread key
62     if ((pthread_key_create(&index, destructor)) != 0)
63     {
64         index = TLS_INVALID_INDEX;
65     }
66 #endif
67 
68     ASSERT(index != TLS_INVALID_INDEX && "CreateTLSIndex: Unable to allocate Thread Local Storage");
69     return index;
70 }
71 
DestroyTLSIndex(TLSIndex index)72 bool DestroyTLSIndex(TLSIndex index)
73 {
74     ASSERT(index != TLS_INVALID_INDEX && "DestroyTLSIndex(): Invalid TLS Index");
75     if (index == TLS_INVALID_INDEX)
76     {
77         return false;
78     }
79 
80 #ifdef ANGLE_PLATFORM_WINDOWS
81 #    ifdef ANGLE_ENABLE_WINDOWS_UWP
82     ASSERT(index < nextTlsIndex);
83     ASSERT(find(freeTlsIndices.begin(), freeTlsIndices.end(), index) == freeTlsIndices.end());
84 
85     freeTlsIndices.push_back(index);
86     for (auto threadData : allThreadData)
87     {
88         if (threadData->size() > index)
89         {
90             threadData->at(index) = nullptr;
91         }
92     }
93     return true;
94 #    else
95     return (TlsFree(index) == TRUE);
96 #    endif
97 #elif defined(ANGLE_PLATFORM_POSIX)
98     return (pthread_key_delete(index) == 0);
99 #endif
100 }
101 
SetTLSValue(TLSIndex index,void * value)102 bool SetTLSValue(TLSIndex index, void *value)
103 {
104     ASSERT(index != TLS_INVALID_INDEX && "SetTLSValue(): Invalid TLS Index");
105     if (index == TLS_INVALID_INDEX)
106     {
107         return false;
108     }
109 
110 #ifdef ANGLE_PLATFORM_WINDOWS
111 #    ifdef ANGLE_ENABLE_WINDOWS_UWP
112     ThreadLocalData *threadData = currentThreadData;
113     if (!threadData)
114     {
115         threadData = new ThreadLocalData(index + 1, nullptr);
116         allThreadData.insert(threadData);
117         currentThreadData = threadData;
118     }
119     else if (threadData->size() <= index)
120     {
121         threadData->resize(index + 1, nullptr);
122     }
123 
124     threadData->at(index) = value;
125     return true;
126 #    else
127     return (TlsSetValue(index, value) == TRUE);
128 #    endif
129 #elif defined(ANGLE_PLATFORM_POSIX)
130     return (pthread_setspecific(index, value) == 0);
131 #endif
132 }
133 
GetTLSValue(TLSIndex index)134 void *GetTLSValue(TLSIndex index)
135 {
136     ASSERT(index != TLS_INVALID_INDEX && "GetTLSValue(): Invalid TLS Index");
137     if (index == TLS_INVALID_INDEX)
138     {
139         return nullptr;
140     }
141 
142 #ifdef ANGLE_PLATFORM_WINDOWS
143 #    ifdef ANGLE_ENABLE_WINDOWS_UWP
144     ThreadLocalData *threadData = currentThreadData;
145     if (threadData && threadData->size() > index)
146     {
147         return threadData->at(index);
148     }
149     else
150     {
151         return nullptr;
152     }
153 #    else
154     return TlsGetValue(index);
155 #    endif
156 #elif defined(ANGLE_PLATFORM_POSIX)
157     return pthread_getspecific(index);
158 #endif
159 }
160 
161 }  // namespace angle
162