180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/*
380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2008 The Android Open Source Project
480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *
580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be
680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file.
780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */
880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include <windows.h>
1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include <intrin.h>
1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkThread.h"
1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkTLS.h"
1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru//MSDN says in order to declare an interlocked function for use as an
1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru//intrinsic, include intrin.h and put the function in a #pragma intrinsic
1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru//directive.
1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru//The pragma appears to be unnecessary, but doesn't hurt.
1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#pragma intrinsic(_InterlockedIncrement, _InterlockedExchangeAdd, _InterlockedDecrement)
2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#pragma intrinsic(_InterlockedCompareExchange)
2180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint32_t sk_atomic_inc(int32_t* addr) {
2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // InterlockedIncrement returns the new value, we want to return the old.
2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return _InterlockedIncrement(reinterpret_cast<LONG*>(addr)) - 1;
2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint32_t sk_atomic_add(int32_t* addr, int32_t inc) {
2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return _InterlockedExchangeAdd(reinterpret_cast<LONG*>(addr),
2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                   static_cast<LONG>(inc));
3080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint32_t sk_atomic_dec(int32_t* addr) {
3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return _InterlockedDecrement(reinterpret_cast<LONG*>(addr)) + 1;
3480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid sk_membar_aquire__after_atomic_dec() { }
3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint32_t sk_atomic_conditional_inc(int32_t* addr) {
3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    while (true) {
3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        LONG value = static_cast<LONG const volatile&>(*addr);
4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (value == 0) {
4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            return 0;
4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (_InterlockedCompareExchange(reinterpret_cast<LONG*>(addr),
4480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                        value + 1,
4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                        value) == value) {
4680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            return value;
4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
4980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
5080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid sk_membar_aquire__after_atomic_conditional_inc() { }
5180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkMutex::SkMutex() {
5380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SK_COMPILE_ASSERT(sizeof(fStorage) > sizeof(CRITICAL_SECTION),
5480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                      NotEnoughSizeForCriticalSection);
5580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    InitializeCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&fStorage));
5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkMutex::~SkMutex() {
5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    DeleteCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&fStorage));
6080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkMutex::acquire() {
6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    EnterCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&fStorage));
6480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkMutex::release() {
6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    LeaveCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&fStorage));
6880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
6980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru///////////////////////////////////////////////////////////////////////////
7180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic bool gOnce;
7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic DWORD gTlsIndex;
7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSK_DECLARE_STATIC_MUTEX(gMutex);
7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid* SkTLS::PlatformGetSpecific(bool forceCreateTheSlot) {
7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (!forceCreateTheSlot && !gOnce) {
7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return NULL;
7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (!gOnce) {
8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkAutoMutexAcquire tmp(gMutex);
8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (!gOnce) {
8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            gTlsIndex = TlsAlloc();
8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            gOnce = true;
8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return TlsGetValue(gTlsIndex);
8980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
9080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkTLS::PlatformSetSpecific(void* ptr) {
9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(gOnce);
9380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    (void)TlsSetValue(gTlsIndex, ptr);
9480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
9580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
96363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger// Call TLS destructors on thread exit. Code based on Chromium's
97363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger// base/threading/thread_local_storage_win.cc
98363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#ifdef _WIN64
99363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
100363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#pragma comment(linker, "/INCLUDE:_tls_used")
101363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#pragma comment(linker, "/INCLUDE:skia_tls_callback")
102363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
103363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#else
104363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
105363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#pragma comment(linker, "/INCLUDE:__tls_used")
106363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#pragma comment(linker, "/INCLUDE:_skia_tls_callback")
107363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
108363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#endif
109363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
110363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergervoid NTAPI onTLSCallback(PVOID unused, DWORD reason, PVOID unused2) {
111363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    if ((DLL_THREAD_DETACH == reason || DLL_PROCESS_DETACH == reason) && gOnce) {
112363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        void* ptr = TlsGetValue(gTlsIndex);
113363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        if (ptr != NULL) {
114363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            SkTLS::Destructor(ptr);
115363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            TlsSetValue(gTlsIndex, NULL);
116363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        }
117363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
118363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger}
119363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
120363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerextern "C" {
121363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
122363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#ifdef _WIN64
123363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
124363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#pragma const_seg(".CRT$XLB")
125363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerextern const PIMAGE_TLS_CALLBACK skia_tls_callback;
126363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerconst PIMAGE_TLS_CALLBACK skia_tls_callback = onTLSCallback;
127363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#pragma const_seg()
128363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
129363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#else
130363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
131363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#pragma data_seg(".CRT$XLB")
132363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek SollenbergerPIMAGE_TLS_CALLBACK skia_tls_callback = onTLSCallback;
133363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#pragma data_seg()
134363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
135363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#endif
136363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger}
137