| // |
| // Copyright 2014 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| |
| // tls.cpp: Simple cross-platform interface for thread local storage. |
| |
| #include "common/tls.h" |
| |
| #include "common/debug.h" |
| |
| #ifdef ANGLE_ENABLE_WINDOWS_UWP |
| # include <map> |
| # include <mutex> |
| # include <set> |
| # include <vector> |
| |
| # include <Windows.System.Threading.h> |
| # include <wrl/async.h> |
| # include <wrl/client.h> |
| |
| using namespace std; |
| using namespace Windows::Foundation; |
| using namespace ABI::Windows::System::Threading; |
| |
| // Thread local storage for Windows Store support |
| typedef vector<void *> ThreadLocalData; |
| |
| static __declspec(thread) ThreadLocalData *currentThreadData = nullptr; |
| static set<ThreadLocalData *> allThreadData; |
| static DWORD nextTlsIndex = 0; |
| static vector<DWORD> freeTlsIndices; |
| |
| #endif |
| |
| bool gUseAndroidOpenGLTlsSlot = false; |
| |
| TLSIndex CreateTLSIndex(PthreadKeyDestructor destructor) |
| { |
| TLSIndex index; |
| |
| #ifdef ANGLE_PLATFORM_WINDOWS |
| # ifdef ANGLE_ENABLE_WINDOWS_UWP |
| if (!freeTlsIndices.empty()) |
| { |
| DWORD result = freeTlsIndices.back(); |
| freeTlsIndices.pop_back(); |
| index = result; |
| } |
| else |
| { |
| index = nextTlsIndex++; |
| } |
| # else |
| index = TlsAlloc(); |
| # endif |
| |
| #elif defined(ANGLE_PLATFORM_POSIX) |
| // Create pthread key |
| if ((pthread_key_create(&index, destructor)) != 0) |
| { |
| index = TLS_INVALID_INDEX; |
| } |
| #endif |
| |
| ASSERT(index != TLS_INVALID_INDEX && "CreateTLSIndex: Unable to allocate Thread Local Storage"); |
| return index; |
| } |
| |
| bool DestroyTLSIndex(TLSIndex index) |
| { |
| ASSERT(index != TLS_INVALID_INDEX && "DestroyTLSIndex(): Invalid TLS Index"); |
| if (index == TLS_INVALID_INDEX) |
| { |
| return false; |
| } |
| |
| #ifdef ANGLE_PLATFORM_WINDOWS |
| # ifdef ANGLE_ENABLE_WINDOWS_UWP |
| ASSERT(index < nextTlsIndex); |
| ASSERT(find(freeTlsIndices.begin(), freeTlsIndices.end(), index) == freeTlsIndices.end()); |
| |
| freeTlsIndices.push_back(index); |
| for (auto threadData : allThreadData) |
| { |
| if (threadData->size() > index) |
| { |
| threadData->at(index) = nullptr; |
| } |
| } |
| return true; |
| # else |
| return (TlsFree(index) == TRUE); |
| # endif |
| #elif defined(ANGLE_PLATFORM_POSIX) |
| return (pthread_key_delete(index) == 0); |
| #endif |
| } |
| |
| bool SetTLSValue(TLSIndex index, void *value) |
| { |
| ASSERT(index != TLS_INVALID_INDEX && "SetTLSValue(): Invalid TLS Index"); |
| if (index == TLS_INVALID_INDEX) |
| { |
| return false; |
| } |
| |
| #ifdef ANGLE_PLATFORM_WINDOWS |
| # ifdef ANGLE_ENABLE_WINDOWS_UWP |
| ThreadLocalData *threadData = currentThreadData; |
| if (!threadData) |
| { |
| threadData = new ThreadLocalData(index + 1, nullptr); |
| allThreadData.insert(threadData); |
| currentThreadData = threadData; |
| } |
| else if (threadData->size() <= index) |
| { |
| threadData->resize(index + 1, nullptr); |
| } |
| |
| threadData->at(index) = value; |
| return true; |
| # else |
| return (TlsSetValue(index, value) == TRUE); |
| # endif |
| #elif defined(ANGLE_PLATFORM_POSIX) |
| return (pthread_setspecific(index, value) == 0); |
| #endif |
| } |
| |
| void *GetTLSValue(TLSIndex index) |
| { |
| ASSERT(index != TLS_INVALID_INDEX && "GetTLSValue(): Invalid TLS Index"); |
| if (index == TLS_INVALID_INDEX) |
| { |
| return nullptr; |
| } |
| |
| #ifdef ANGLE_PLATFORM_WINDOWS |
| # ifdef ANGLE_ENABLE_WINDOWS_UWP |
| ThreadLocalData *threadData = currentThreadData; |
| if (threadData && threadData->size() > index) |
| { |
| return threadData->at(index); |
| } |
| else |
| { |
| return nullptr; |
| } |
| # else |
| return TlsGetValue(index); |
| # endif |
| #elif defined(ANGLE_PLATFORM_POSIX) |
| return pthread_getspecific(index); |
| #endif |
| } |