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 <vector> 15 #include <set> 16 #include <map> 17 #include <mutex> 18 19 #include <wrl/client.h> 20 #include <wrl/async.h> 21 #include <Windows.System.Threading.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()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 && "CreateTLSIndex(): Unable to allocate Thread Local Storage"); 66 return index; 67 } 68 DestroyTLSIndex(TLSIndex index)69bool DestroyTLSIndex(TLSIndex index) 70 { 71 assert(index != TLS_INVALID_INDEX && "DestroyTLSIndex(): Invalid TLS Index"); 72 if (index == TLS_INVALID_INDEX) 73 { 74 return false; 75 } 76 77 #ifdef ANGLE_PLATFORM_WINDOWS 78 #ifdef ANGLE_ENABLE_WINDOWS_STORE 79 assert(index < nextTlsIndex); 80 assert(find(freeTlsIndices.begin(), freeTlsIndices.end(), index) == freeTlsIndices.end()); 81 82 freeTlsIndices.push_back(index); 83 for (auto threadData : allThreadData) 84 { 85 if (threadData->size() > index) 86 { 87 threadData->at(index) = nullptr; 88 } 89 } 90 return true; 91 #else 92 return (TlsFree(index) == TRUE); 93 #endif 94 #elif defined(ANGLE_PLATFORM_POSIX) 95 return (pthread_key_delete(index) == 0); 96 #endif 97 } 98 SetTLSValue(TLSIndex index,void * value)99bool SetTLSValue(TLSIndex index, void *value) 100 { 101 assert(index != TLS_INVALID_INDEX && "SetTLSValue(): Invalid TLS Index"); 102 if (index == TLS_INVALID_INDEX) 103 { 104 return false; 105 } 106 107 #ifdef ANGLE_PLATFORM_WINDOWS 108 #ifdef ANGLE_ENABLE_WINDOWS_STORE 109 ThreadLocalData* threadData = currentThreadData; 110 if (!threadData) 111 { 112 threadData = new ThreadLocalData(index + 1, nullptr); 113 allThreadData.insert(threadData); 114 currentThreadData = threadData; 115 } 116 else if (threadData->size() <= index) 117 { 118 threadData->resize(index + 1, nullptr); 119 } 120 121 threadData->at(index) = value; 122 return true; 123 #else 124 return (TlsSetValue(index, value) == TRUE); 125 #endif 126 #elif defined(ANGLE_PLATFORM_POSIX) 127 return (pthread_setspecific(index, value) == 0); 128 #endif 129 } 130 GetTLSValue(TLSIndex index)131void *GetTLSValue(TLSIndex index) 132 { 133 assert(index != TLS_INVALID_INDEX && "GetTLSValue(): Invalid TLS Index"); 134 if (index == TLS_INVALID_INDEX) 135 { 136 return nullptr; 137 } 138 139 #ifdef ANGLE_PLATFORM_WINDOWS 140 #ifdef ANGLE_ENABLE_WINDOWS_STORE 141 ThreadLocalData* threadData = currentThreadData; 142 if (threadData && threadData->size() > index) 143 { 144 return threadData->at(index); 145 } 146 else 147 { 148 return nullptr; 149 } 150 #else 151 return TlsGetValue(index); 152 #endif 153 #elif defined(ANGLE_PLATFORM_POSIX) 154 return pthread_getspecific(index); 155 #endif 156 } 157