1/*
2 * Copyright 2008 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include <windows.h>
9#include <intrin.h>
10#include "SkThread.h"
11
12//MSDN says in order to declare an interlocked function for use as an
13//intrinsic, include intrin.h and put the function in a #pragma intrinsic
14//directive.
15//The pragma appears to be unnecessary, but doesn't hurt.
16#pragma intrinsic(_InterlockedIncrement, _InterlockedExchangeAdd, _InterlockedDecrement)
17#pragma intrinsic(_InterlockedCompareExchange)
18
19int32_t sk_atomic_inc(int32_t* addr) {
20    // InterlockedIncrement returns the new value, we want to return the old.
21    return _InterlockedIncrement(reinterpret_cast<LONG*>(addr)) - 1;
22}
23
24int32_t sk_atomic_add(int32_t* addr, int32_t inc) {
25    return _InterlockedExchangeAdd(reinterpret_cast<LONG*>(addr),
26                                   static_cast<LONG>(inc));
27}
28
29int32_t sk_atomic_dec(int32_t* addr) {
30    return _InterlockedDecrement(reinterpret_cast<LONG*>(addr)) + 1;
31}
32void sk_membar_aquire__after_atomic_dec() { }
33
34int32_t sk_atomic_conditional_inc(int32_t* addr) {
35    while (true) {
36        LONG value = static_cast<int32_t const volatile&>(*addr);
37        if (value == 0) {
38            return 0;
39        }
40        if (_InterlockedCompareExchange(reinterpret_cast<LONG*>(addr),
41                                        value + 1,
42                                        value) == value) {
43            return value;
44        }
45    }
46}
47void sk_membar_aquire__after_atomic_conditional_inc() { }
48
49SkMutex::SkMutex() {
50    SK_COMPILE_ASSERT(sizeof(fStorage) > sizeof(CRITICAL_SECTION),
51                      NotEnoughSizeForCriticalSection);
52    InitializeCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&fStorage));
53}
54
55SkMutex::~SkMutex() {
56    DeleteCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&fStorage));
57}
58
59void SkMutex::acquire() {
60    EnterCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&fStorage));
61}
62
63void SkMutex::release() {
64    LeaveCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&fStorage));
65}
66