tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

global_state.cpp (10006B)


      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 // global_state.cpp : Implements functions for querying the thread-local GL and EGL state.
      8 
      9 #include "libGLESv2/global_state.h"
     10 
     11 #include "common/debug.h"
     12 #include "common/platform.h"
     13 #include "common/system_utils.h"
     14 #include "libANGLE/ErrorStrings.h"
     15 #include "libANGLE/Thread.h"
     16 #include "libGLESv2/resource.h"
     17 
     18 #include <atomic>
     19 #if defined(ANGLE_PLATFORM_APPLE)
     20 #    include <dispatch/dispatch.h>
     21 #endif
     22 namespace egl
     23 {
     24 namespace
     25 {
     26 ANGLE_REQUIRE_CONSTANT_INIT std::atomic<angle::GlobalMutex *> g_Mutex{};
     27 static_assert(std::is_trivially_destructible<decltype(g_Mutex)>::value,
     28              "global mutex is not trivially destructible");
     29 ANGLE_REQUIRE_CONSTANT_INIT std::atomic<angle::GlobalMutex *> g_SurfaceMutex{};
     30 static_assert(std::is_trivially_destructible<decltype(g_SurfaceMutex)>::value,
     31              "global mutex is not trivially destructible");
     32 
     33 ANGLE_REQUIRE_CONSTANT_INIT gl::Context *g_LastContext(nullptr);
     34 static_assert(std::is_trivially_destructible<decltype(g_LastContext)>::value,
     35              "global last context is not trivially destructible");
     36 
     37 void SetContextToAndroidOpenGLTLSSlot(gl::Context *value)
     38 {
     39 #if defined(ANGLE_USE_ANDROID_TLS_SLOT)
     40    if (angle::gUseAndroidOpenGLTlsSlot)
     41    {
     42        ANGLE_ANDROID_GET_GL_TLS()[angle::kAndroidOpenGLTlsSlot] = static_cast<void *>(value);
     43    }
     44 #endif
     45 }
     46 
     47 // Called only on Android platform
     48 [[maybe_unused]] void ThreadCleanupCallback(void *ptr)
     49 {
     50    ANGLE_SCOPED_GLOBAL_LOCK();
     51    angle::PthreadKeyDestructorCallback(ptr);
     52 }
     53 
     54 Thread *AllocateCurrentThread()
     55 {
     56    Thread *thread;
     57    {
     58        // Global thread intentionally leaked
     59        ANGLE_SCOPED_DISABLE_LSAN();
     60        thread = new Thread();
     61 #if defined(ANGLE_PLATFORM_APPLE)
     62        SetCurrentThreadTLS(thread);
     63 #else
     64        gCurrentThread = thread;
     65 #endif
     66    }
     67 
     68    // Initialize fast TLS slot
     69    SetContextToAndroidOpenGLTLSSlot(nullptr);
     70 
     71 #if defined(ANGLE_PLATFORM_APPLE)
     72    gl::SetCurrentValidContextTLS(nullptr);
     73 #else
     74    gl::gCurrentValidContext = nullptr;
     75 #endif
     76 
     77 #if defined(ANGLE_PLATFORM_ANDROID)
     78    static pthread_once_t keyOnce          = PTHREAD_ONCE_INIT;
     79    static TLSIndex gThreadCleanupTLSIndex = TLS_INVALID_INDEX;
     80 
     81    // Create thread cleanup TLS slot
     82    auto CreateThreadCleanupTLSIndex = []() {
     83        gThreadCleanupTLSIndex = CreateTLSIndex(ThreadCleanupCallback);
     84    };
     85    pthread_once(&keyOnce, CreateThreadCleanupTLSIndex);
     86    ASSERT(gThreadCleanupTLSIndex != TLS_INVALID_INDEX);
     87 
     88    // Initialize thread cleanup TLS slot
     89    SetTLSValue(gThreadCleanupTLSIndex, thread);
     90 #endif  // ANGLE_PLATFORM_ANDROID
     91 
     92    ASSERT(thread);
     93    return thread;
     94 }
     95 
     96 void AllocateGlobalMutex(std::atomic<angle::GlobalMutex *> &mutex)
     97 {
     98    if (mutex == nullptr)
     99    {
    100        std::unique_ptr<angle::GlobalMutex> newMutex(new angle::GlobalMutex());
    101        angle::GlobalMutex *expected = nullptr;
    102        if (mutex.compare_exchange_strong(expected, newMutex.get()))
    103        {
    104            newMutex.release();
    105        }
    106    }
    107 }
    108 
    109 void AllocateMutex()
    110 {
    111    AllocateGlobalMutex(g_Mutex);
    112 }
    113 
    114 void AllocateSurfaceMutex()
    115 {
    116    AllocateGlobalMutex(g_SurfaceMutex);
    117 }
    118 
    119 }  // anonymous namespace
    120 
    121 #if defined(ANGLE_PLATFORM_APPLE)
    122 // TODO(angleproject:6479): Due to a bug in Apple's dyld loader, `thread_local` will cause
    123 // excessive memory use. Temporarily avoid it by using pthread's thread
    124 // local storage instead.
    125 // https://bugs.webkit.org/show_bug.cgi?id=228240
    126 
    127 static TLSIndex GetCurrentThreadTLSIndex()
    128 {
    129    static TLSIndex CurrentThreadIndex = TLS_INVALID_INDEX;
    130    static dispatch_once_t once;
    131    dispatch_once(&once, ^{
    132      ASSERT(CurrentThreadIndex == TLS_INVALID_INDEX);
    133      CurrentThreadIndex = CreateTLSIndex(nullptr);
    134    });
    135    return CurrentThreadIndex;
    136 }
    137 Thread *GetCurrentThreadTLS()
    138 {
    139    TLSIndex CurrentThreadIndex = GetCurrentThreadTLSIndex();
    140    ASSERT(CurrentThreadIndex != TLS_INVALID_INDEX);
    141    return static_cast<Thread *>(GetTLSValue(CurrentThreadIndex));
    142 }
    143 void SetCurrentThreadTLS(Thread *thread)
    144 {
    145    TLSIndex CurrentThreadIndex = GetCurrentThreadTLSIndex();
    146    ASSERT(CurrentThreadIndex != TLS_INVALID_INDEX);
    147    SetTLSValue(CurrentThreadIndex, thread);
    148 }
    149 #else
    150 thread_local Thread *gCurrentThread = nullptr;
    151 #endif
    152 
    153 angle::GlobalMutex &GetGlobalMutex()
    154 {
    155    AllocateMutex();
    156    return *g_Mutex;
    157 }
    158 
    159 angle::GlobalMutex &GetGlobalSurfaceMutex()
    160 {
    161    AllocateSurfaceMutex();
    162    return *g_SurfaceMutex;
    163 }
    164 
    165 gl::Context *GetGlobalLastContext()
    166 {
    167    return g_LastContext;
    168 }
    169 
    170 void SetGlobalLastContext(gl::Context *context)
    171 {
    172    g_LastContext = context;
    173 }
    174 
    175 // This function causes an MSAN false positive, which is muted. See https://crbug.com/1211047
    176 // It also causes a flaky false positive in TSAN. http://crbug.com/1223970
    177 ANGLE_NO_SANITIZE_MEMORY ANGLE_NO_SANITIZE_THREAD Thread *GetCurrentThread()
    178 {
    179 #if defined(ANGLE_PLATFORM_APPLE)
    180    Thread *current = GetCurrentThreadTLS();
    181 #else
    182    Thread *current = gCurrentThread;
    183 #endif
    184    return (current ? current : AllocateCurrentThread());
    185 }
    186 
    187 void SetContextCurrent(Thread *thread, gl::Context *context)
    188 {
    189 #if defined(ANGLE_PLATFORM_APPLE)
    190    Thread *currentThread = GetCurrentThreadTLS();
    191 #else
    192    Thread *currentThread = gCurrentThread;
    193 #endif
    194    ASSERT(currentThread);
    195    currentThread->setCurrent(context);
    196    SetContextToAndroidOpenGLTLSSlot(context);
    197 
    198 #if defined(ANGLE_PLATFORM_APPLE)
    199    gl::SetCurrentValidContextTLS(context);
    200 #else
    201    gl::gCurrentValidContext = context;
    202 #endif
    203 
    204 #if defined(ANGLE_FORCE_CONTEXT_CHECK_EVERY_CALL)
    205    DirtyContextIfNeeded(context);
    206 #endif
    207 }
    208 
    209 ScopedSyncCurrentContextFromThread::ScopedSyncCurrentContextFromThread(egl::Thread *thread)
    210    : mThread(thread)
    211 {
    212    ASSERT(mThread);
    213 }
    214 
    215 ScopedSyncCurrentContextFromThread::~ScopedSyncCurrentContextFromThread()
    216 {
    217    SetContextCurrent(mThread, mThread->getContext());
    218 }
    219 
    220 }  // namespace egl
    221 
    222 namespace gl
    223 {
    224 void GenerateContextLostErrorOnContext(Context *context)
    225 {
    226    if (context && context->isContextLost())
    227    {
    228        context->validationError(angle::EntryPoint::GLInvalid, GL_CONTEXT_LOST, err::kContextLost);
    229    }
    230 }
    231 
    232 void GenerateContextLostErrorOnCurrentGlobalContext()
    233 {
    234    // If the client starts issuing GL calls before ANGLE has had a chance to initialize,
    235    // GenerateContextLostErrorOnCurrentGlobalContext can be called before AllocateCurrentThread has
    236    // had a chance to run. Calling GetCurrentThread() ensures that TLS thread state is set up.
    237    egl::GetCurrentThread();
    238 
    239    GenerateContextLostErrorOnContext(GetGlobalContext());
    240 }
    241 }  // namespace gl
    242 
    243 #if defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_STATIC)
    244 namespace egl
    245 {
    246 
    247 namespace
    248 {
    249 
    250 void DeallocateGlobalMutex(std::atomic<angle::GlobalMutex *> &mutex)
    251 {
    252    angle::GlobalMutex *toDelete = mutex.exchange(nullptr);
    253    if (!mutex)
    254        return;
    255    {
    256        // Wait for toDelete to become released by other threads before deleting.
    257        std::lock_guard<angle::GlobalMutex> lock(*toDelete);
    258    }
    259    SafeDelete(toDelete);
    260 }
    261 
    262 void DeallocateCurrentThread()
    263 {
    264    SafeDelete(gCurrentThread);
    265 }
    266 
    267 void DeallocateMutex()
    268 {
    269    DeallocateGlobalMutex(g_Mutex);
    270 }
    271 
    272 void DeallocateSurfaceMutex()
    273 {
    274    DeallocateGlobalMutex(g_SurfaceMutex);
    275 }
    276 
    277 bool InitializeProcess()
    278 {
    279    EnsureDebugAllocated();
    280    AllocateMutex();
    281    return AllocateCurrentThread() != nullptr;
    282 }
    283 
    284 void TerminateProcess()
    285 {
    286    DeallocateDebug();
    287    DeallocateSurfaceMutex();
    288    DeallocateMutex();
    289    DeallocateCurrentThread();
    290 }
    291 
    292 }  // anonymous namespace
    293 
    294 }  // namespace egl
    295 
    296 namespace
    297 {
    298 // The following WaitForDebugger code is based on SwiftShader. See:
    299 // https://cs.chromium.org/chromium/src/third_party/swiftshader/src/Vulkan/main.cpp
    300 #    if defined(ANGLE_ENABLE_ASSERTS) && !defined(ANGLE_ENABLE_WINDOWS_UWP)
    301 INT_PTR CALLBACK DebuggerWaitDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    302 {
    303    RECT rect;
    304 
    305    switch (uMsg)
    306    {
    307        case WM_INITDIALOG:
    308            ::GetWindowRect(GetDesktopWindow(), &rect);
    309            ::SetWindowPos(hwnd, HWND_TOP, rect.right / 2, rect.bottom / 2, 0, 0, SWP_NOSIZE);
    310            ::SetTimer(hwnd, 1, 100, NULL);
    311            return TRUE;
    312        case WM_COMMAND:
    313            if (LOWORD(wParam) == IDCANCEL)
    314            {
    315                ::EndDialog(hwnd, 0);
    316            }
    317            break;
    318        case WM_TIMER:
    319            if (angle::IsDebuggerAttached())
    320            {
    321                ::EndDialog(hwnd, 0);
    322            }
    323    }
    324 
    325    return FALSE;
    326 }
    327 
    328 void WaitForDebugger(HINSTANCE instance)
    329 {
    330    if (angle::IsDebuggerAttached())
    331        return;
    332 
    333    HRSRC dialog = ::FindResourceA(instance, MAKEINTRESOURCEA(IDD_DIALOG1), MAKEINTRESOURCEA(5));
    334    if (!dialog)
    335    {
    336        printf("Error finding wait for debugger dialog. Error %lu.\n", ::GetLastError());
    337        return;
    338    }
    339 
    340    DLGTEMPLATE *dialogTemplate = reinterpret_cast<DLGTEMPLATE *>(::LoadResource(instance, dialog));
    341    ::DialogBoxIndirectA(instance, dialogTemplate, NULL, DebuggerWaitDialogProc);
    342 }
    343 #    else
    344 void WaitForDebugger(HINSTANCE instance) {}
    345 #    endif  // defined(ANGLE_ENABLE_ASSERTS) && !defined(ANGLE_ENABLE_WINDOWS_UWP)
    346 }  // namespace
    347 
    348 extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID)
    349 {
    350    switch (reason)
    351    {
    352        case DLL_PROCESS_ATTACH:
    353            if (angle::GetEnvironmentVar("ANGLE_WAIT_FOR_DEBUGGER") == "1")
    354            {
    355                WaitForDebugger(instance);
    356            }
    357            return static_cast<BOOL>(egl::InitializeProcess());
    358 
    359        case DLL_THREAD_ATTACH:
    360            return static_cast<BOOL>(egl::AllocateCurrentThread() != nullptr);
    361 
    362        case DLL_THREAD_DETACH:
    363            egl::DeallocateCurrentThread();
    364            break;
    365 
    366        case DLL_PROCESS_DETACH:
    367            egl::TerminateProcess();
    368            break;
    369    }
    370 
    371    return TRUE;
    372 }
    373 #endif  // defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_STATIC)