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)40TLSIndex 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)72bool 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)102bool 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)134void *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