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()37TLSIndex 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)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_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)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_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)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_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