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)39TLSIndex 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)71bool 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)101bool 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)133void *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