1 2 /* 3 * Copyright 2008 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 #include <windows.h> 11 #include <intrin.h> 12 #include "SkThread.h" 13 #include "SkTLS.h" 14 15 //MSDN says in order to declare an interlocked function for use as an 16 //intrinsic, include intrin.h and put the function in a #pragma intrinsic 17 //directive. 18 //The pragma appears to be unnecessary, but doesn't hurt. 19 #pragma intrinsic(_InterlockedIncrement, _InterlockedExchangeAdd, _InterlockedDecrement) 20 #pragma intrinsic(_InterlockedCompareExchange) 21 22 int32_t sk_atomic_inc(int32_t* addr) { 23 // InterlockedIncrement returns the new value, we want to return the old. 24 return _InterlockedIncrement(reinterpret_cast<LONG*>(addr)) - 1; 25 } 26 27 int32_t sk_atomic_add(int32_t* addr, int32_t inc) { 28 return _InterlockedExchangeAdd(reinterpret_cast<LONG*>(addr), 29 static_cast<LONG>(inc)); 30 } 31 32 int32_t sk_atomic_dec(int32_t* addr) { 33 return _InterlockedDecrement(reinterpret_cast<LONG*>(addr)) + 1; 34 } 35 void sk_membar_aquire__after_atomic_dec() { } 36 37 int32_t sk_atomic_conditional_inc(int32_t* addr) { 38 while (true) { 39 LONG value = static_cast<LONG const volatile&>(*addr); 40 if (value == 0) { 41 return 0; 42 } 43 if (_InterlockedCompareExchange(reinterpret_cast<LONG*>(addr), 44 value + 1, 45 value) == value) { 46 return value; 47 } 48 } 49 } 50 void sk_membar_aquire__after_atomic_conditional_inc() { } 51 52 SkMutex::SkMutex() { 53 SK_COMPILE_ASSERT(sizeof(fStorage) > sizeof(CRITICAL_SECTION), 54 NotEnoughSizeForCriticalSection); 55 InitializeCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&fStorage)); 56 } 57 58 SkMutex::~SkMutex() { 59 DeleteCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&fStorage)); 60 } 61 62 void SkMutex::acquire() { 63 EnterCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&fStorage)); 64 } 65 66 void SkMutex::release() { 67 LeaveCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&fStorage)); 68 } 69 70 /////////////////////////////////////////////////////////////////////////// 71 72 static bool gOnce; 73 static DWORD gTlsIndex; 74 SK_DECLARE_STATIC_MUTEX(gMutex); 75 76 void* SkTLS::PlatformGetSpecific(bool forceCreateTheSlot) { 77 if (!forceCreateTheSlot && !gOnce) { 78 return NULL; 79 } 80 81 if (!gOnce) { 82 SkAutoMutexAcquire tmp(gMutex); 83 if (!gOnce) { 84 gTlsIndex = TlsAlloc(); 85 gOnce = true; 86 } 87 } 88 return TlsGetValue(gTlsIndex); 89 } 90 91 void SkTLS::PlatformSetSpecific(void* ptr) { 92 SkASSERT(gOnce); 93 (void)TlsSetValue(gTlsIndex, ptr); 94 } 95 96 // Call TLS destructors on thread exit. Code based on Chromium's 97 // base/threading/thread_local_storage_win.cc 98 #ifdef _WIN64 99 100 #pragma comment(linker, "/INCLUDE:_tls_used") 101 #pragma comment(linker, "/INCLUDE:skia_tls_callback") 102 103 #else 104 105 #pragma comment(linker, "/INCLUDE:__tls_used") 106 #pragma comment(linker, "/INCLUDE:_skia_tls_callback") 107 108 #endif 109 110 void NTAPI onTLSCallback(PVOID unused, DWORD reason, PVOID unused2) { 111 if ((DLL_THREAD_DETACH == reason || DLL_PROCESS_DETACH == reason) && gOnce) { 112 void* ptr = TlsGetValue(gTlsIndex); 113 if (ptr != NULL) { 114 SkTLS::Destructor(ptr); 115 TlsSetValue(gTlsIndex, NULL); 116 } 117 } 118 } 119 120 extern "C" { 121 122 #ifdef _WIN64 123 124 #pragma const_seg(".CRT$XLB") 125 extern const PIMAGE_TLS_CALLBACK skia_tls_callback; 126 const PIMAGE_TLS_CALLBACK skia_tls_callback = onTLSCallback; 127 #pragma const_seg() 128 129 #else 130 131 #pragma data_seg(".CRT$XLB") 132 PIMAGE_TLS_CALLBACK skia_tls_callback = onTLSCallback; 133 #pragma data_seg() 134 135 #endif 136 } 137