Home | History | Annotate | Download | only in ports
      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