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