Edit

kc3-lang/angle/src/common/tls.cpp

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2020-09-20 21:59:24
    Hash : cb286073
    Message : Use c++ thread_local for current thread. This solves a race condition using the global context. Sadly we can't use an unprotected variable safely because it can be written/read from multiple threads doing MakeCurrent. Has about a 2 ns regression when tested in Linux/Release per call. "null" benchmark test went from 27 -> 29 ns/iteration. Fixes a TSAN warning that popped up in angle_end2end_tests. Test: DrawCallPerfBenchmark.Run/vulkan_null Test: EGLContextASANTest.DestroyContextInUse/ES3_Vulkan Bug: b/168744561 Change-Id: Ic56f3faae81c1087b942a3cfc0e011b9ab439e0f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2419641 Reviewed-by: Geoff Lang <geofflang@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • src/common/tls.cpp
  • //
    // 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()
    {
        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 global pool key
        if ((pthread_key_create(&index, nullptr)) != 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
    }