1//
2// Copyright (c) 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 <assert.h>
12
13#ifdef ANGLE_ENABLE_WINDOWS_STORE
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
23using namespace std;
24using namespace Windows::Foundation;
25using namespace ABI::Windows::System::Threading;
26
27// Thread local storage for Windows Store support
28typedef vector<void *> ThreadLocalData;
29
30static __declspec(thread) ThreadLocalData *currentThreadData = nullptr;
31static set<ThreadLocalData *> allThreadData;
32static DWORD nextTlsIndex = 0;
33static vector<DWORD> freeTlsIndices;
34
35#endif
36
37TLSIndex CreateTLSIndex()
38{
39 TLSIndex index;
40
41#ifdef ANGLE_PLATFORM_WINDOWS
42# ifdef ANGLE_ENABLE_WINDOWS_STORE
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
70bool 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_STORE
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
100bool 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_STORE
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
132void *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_STORE
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