aboutsummaryrefslogtreecommitdiffhomepage
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/config/SkUserConfig.h10
-rw-r--r--include/core/SkAtomics.h13
-rw-r--r--include/core/SkBarriers.h15
-rw-r--r--include/core/SkMutex.h13
-rw-r--r--include/core/SkPostConfig.h28
-rw-r--r--include/core/SkThread.h25
-rw-r--r--include/core/SkThreadPriv.h8
-rw-r--r--include/ports/SkAtomics_sync.h55
-rw-r--r--include/ports/SkAtomics_win.h54
-rw-r--r--include/ports/SkBarriers_arm.h36
-rw-r--r--include/ports/SkBarriers_tsan.h31
-rw-r--r--include/ports/SkBarriers_x86.h39
-rw-r--r--include/ports/SkMutex_pthread.h96
-rw-r--r--include/ports/SkMutex_win.h79
14 files changed, 439 insertions, 63 deletions
diff --git a/include/config/SkUserConfig.h b/include/config/SkUserConfig.h
index 5f59b9131c..92e2b90762 100644
--- a/include/config/SkUserConfig.h
+++ b/include/config/SkUserConfig.h
@@ -168,14 +168,4 @@
*/
//#define SK_PDF_USE_PATHOPS
-/* Skia uses these defines as the target of include preprocessor directives.
- * The header files pointed to by these defines provide declarations and
- * possibly inline implementations of threading primitives.
- *
- * See SkThread.h for documentation on what these includes must contain.
- */
-//#define SK_ATOMICS_PLATFORM_H "SkAtomics_xxx.h"
-//#define SK_MUTEX_PLATFORM_H "SkMutex_xxx.h"
-//#define SK_BARRIERS_PLATFORM_H "SkBarriers_xxx.h"
-
#endif
diff --git a/include/core/SkAtomics.h b/include/core/SkAtomics.h
new file mode 100644
index 0000000000..ed19533163
--- /dev/null
+++ b/include/core/SkAtomics.h
@@ -0,0 +1,13 @@
+#ifndef SkAtomics_DEFINED
+#define SkAtomics_DEFINED
+
+// This file is not part of the public Skia API.
+#include "SkTypes.h"
+
+#if defined(_MSC_VER)
+ #include "../ports/SkAtomics_win.h"
+#else
+ #include "../ports/SkAtomics_sync.h"
+#endif
+
+#endif//SkAtomics_DEFINED
diff --git a/include/core/SkBarriers.h b/include/core/SkBarriers.h
new file mode 100644
index 0000000000..2067a829a3
--- /dev/null
+++ b/include/core/SkBarriers.h
@@ -0,0 +1,15 @@
+#ifndef SkBarriers_DEFINED
+#define SkBarriers_DEFINED
+
+// This file is not part of the public Skia API.
+#include "SkTypes.h"
+
+#if SK_HAS_COMPILER_FEATURE(thread_sanitizer)
+ #include "../ports/SkBarriers_tsan.h"
+#elif defined(SK_CPU_ARM32) || defined(SK_CPU_ARM64)
+ #include "../ports/SkBarriers_arm.h"
+#else
+ #include "../ports/SkBarriers_x86.h"
+#endif
+
+#endif//SkBarriers_DEFINED
diff --git a/include/core/SkMutex.h b/include/core/SkMutex.h
new file mode 100644
index 0000000000..7dbe957d8b
--- /dev/null
+++ b/include/core/SkMutex.h
@@ -0,0 +1,13 @@
+#ifndef SkMutex_DEFINED
+#define SkMutex_DEFINED
+
+// This file is not part of the public Skia API.
+#include "SkTypes.h"
+
+#if defined(SK_BUILD_FOR_WIN)
+ #include "../ports/SkMutex_win.h"
+#else
+ #include "../ports/SkMutex_pthread.h"
+#endif
+
+#endif//SkMutex_DEFINED
diff --git a/include/core/SkPostConfig.h b/include/core/SkPostConfig.h
index 2d6ab44b65..de63c671bd 100644
--- a/include/core/SkPostConfig.h
+++ b/include/core/SkPostConfig.h
@@ -385,34 +385,6 @@
//////////////////////////////////////////////////////////////////////
-#ifndef SK_ATOMICS_PLATFORM_H
-# if defined(_MSC_VER)
-# define SK_ATOMICS_PLATFORM_H "../../src/ports/SkAtomics_win.h"
-# else
-# define SK_ATOMICS_PLATFORM_H "../../src/ports/SkAtomics_sync.h"
-# endif
-#endif
-
-#ifndef SK_MUTEX_PLATFORM_H
-# if defined(SK_BUILD_FOR_WIN)
-# define SK_MUTEX_PLATFORM_H "../../src/ports/SkMutex_win.h"
-# else
-# define SK_MUTEX_PLATFORM_H "../../src/ports/SkMutex_pthread.h"
-# endif
-#endif
-
-#ifndef SK_BARRIERS_PLATFORM_H
-# if SK_HAS_COMPILER_FEATURE(thread_sanitizer)
-# define SK_BARRIERS_PLATFORM_H "../../src/ports/SkBarriers_tsan.h"
-# elif defined(SK_CPU_ARM32) || defined(SK_CPU_ARM64)
-# define SK_BARRIERS_PLATFORM_H "../../src/ports/SkBarriers_arm.h"
-# else
-# define SK_BARRIERS_PLATFORM_H "../../src/ports/SkBarriers_x86.h"
-# endif
-#endif
-
-//////////////////////////////////////////////////////////////////////
-
#ifndef SK_EGL
# if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_NACL)
# define SK_EGL 1
diff --git a/include/core/SkThread.h b/include/core/SkThread.h
index fffe787e71..8d7fb3912c 100644
--- a/include/core/SkThread.h
+++ b/include/core/SkThread.h
@@ -10,7 +10,7 @@
#include "SkTypes.h"
-// SK_ATOMICS_PLATFORM_H must provide inline implementations for the following declarations.
+// SkAtomics.h must provide inline implementations for the following declarations.
/** Atomically adds one to the int referenced by addr and returns the previous value.
* No additional memory barrier is required; this must act as a compiler barrier.
@@ -44,11 +44,7 @@ static void sk_membar_acquire__after_atomic_dec();
*/
static void sk_membar_acquire__after_atomic_conditional_inc();
-#ifdef GOOGLE3
- #include "SkAtomics_sync.h"
-#else
- #include SK_ATOMICS_PLATFORM_H
-#endif
+#include "SkAtomics.h"
/** Atomically adds one to the int referenced by addr iff the referenced int was not 0
* and returns the previous value.
@@ -65,7 +61,7 @@ template<typename INT_TYPE> static inline INT_TYPE sk_atomic_conditional_inc(INT
return prev;
}
-// SK_BARRIERS_PLATFORM_H must provide implementations for the following declarations:
+// SkBarriers.h must provide implementations for the following declarations:
/** Prevent the compiler from reordering across this barrier. */
static void sk_compiler_barrier();
@@ -82,13 +78,9 @@ template <typename T> T sk_acquire_load(T*);
*/
template <typename T> void sk_release_store(T*, T);
-#ifdef GOOGLE3
- #include "SkBarriers_x86.h"
-#else
- #include SK_BARRIERS_PLATFORM_H
-#endif
+#include "SkBarriers.h"
-/** SK_MUTEX_PLATFORM_H must provide the following (or equivalent) declarations.
+/** SkMutex.h must provide the following (or equivalent) declarations.
class SkBaseMutex {
public:
@@ -106,12 +98,7 @@ public:
#define SK_DECLARE_STATIC_MUTEX(name) static SkBaseMutex name = ...
*/
-#ifdef GOOGLE3
- #include "SkMutex_pthread.h"
-#else
- #include SK_MUTEX_PLATFORM_H
-#endif
-
+#include "SkMutex.h"
class SkAutoMutexAcquire : SkNoncopyable {
public:
diff --git a/include/core/SkThreadPriv.h b/include/core/SkThreadPriv.h
index ab40731dc0..09d5a669f1 100644
--- a/include/core/SkThreadPriv.h
+++ b/include/core/SkThreadPriv.h
@@ -10,7 +10,7 @@
#include "SkTypes.h"
-// SK_ATOMICS_PLATFORM_H must provide inline implementations for the following declarations.
+// SkAtomics.h must provide inline implementations for the following declarations.
/** Atomic compare and set, for pointers.
* If *addr == before, set *addr to after. Always returns previous value of *addr.
@@ -18,10 +18,6 @@
*/
static void* sk_atomic_cas(void** addr, void* before, void* after);
-#ifdef GOOGLE3
- #include "SkAtomics_sync.h"
-#else
- #include SK_ATOMICS_PLATFORM_H
-#endif
+#include "SkAtomics.h"
#endif//SkThreadPriv_DEFINED
diff --git a/include/ports/SkAtomics_sync.h b/include/ports/SkAtomics_sync.h
new file mode 100644
index 0000000000..9389c00103
--- /dev/null
+++ b/include/ports/SkAtomics_sync.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkAtomics_sync_DEFINED
+#define SkAtomics_sync_DEFINED
+
+/** GCC/Clang __sync based atomics. */
+
+#include <stdint.h>
+
+static inline __attribute__((always_inline)) int32_t sk_atomic_inc(int32_t* addr) {
+ return __sync_fetch_and_add(addr, 1);
+}
+
+static inline __attribute__((always_inline)) int64_t sk_atomic_inc(int64_t* addr) {
+#if defined(__mips__) && !defined(__LP64__) && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)
+ /** Some versions of the GCC 32-bit MIPS toolchains (e.g. 4.8) for android are missing
+ * support for the __sync* functions that operate on 64-bit values. The workaround
+ * is to use __atomic* functions until we can move everything to <stdatomic.h>.
+ */
+ return __atomic_fetch_add(addr, 1, __ATOMIC_SEQ_CST);
+#else
+ return __sync_fetch_and_add(addr, 1);
+#endif
+}
+
+static inline __attribute__((always_inline)) int32_t sk_atomic_add(int32_t* addr, int32_t inc) {
+ return __sync_fetch_and_add(addr, inc);
+}
+
+static inline __attribute__((always_inline)) int32_t sk_atomic_dec(int32_t* addr) {
+ return __sync_fetch_and_add(addr, -1);
+}
+
+static inline __attribute__((always_inline)) void sk_membar_acquire__after_atomic_dec() { }
+
+static inline __attribute__((always_inline)) bool sk_atomic_cas(int32_t* addr,
+ int32_t before,
+ int32_t after) {
+ return __sync_bool_compare_and_swap(addr, before, after);
+}
+
+static inline __attribute__((always_inline)) void* sk_atomic_cas(void** addr,
+ void* before,
+ void* after) {
+ return __sync_val_compare_and_swap(addr, before, after);
+}
+
+static inline __attribute__((always_inline)) void sk_membar_acquire__after_atomic_conditional_inc() { }
+
+#endif
diff --git a/include/ports/SkAtomics_win.h b/include/ports/SkAtomics_win.h
new file mode 100644
index 0000000000..a1876d269b
--- /dev/null
+++ b/include/ports/SkAtomics_win.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkAtomics_win_DEFINED
+#define SkAtomics_win_DEFINED
+
+/** Windows Interlocked atomics. */
+
+#include <intrin.h>
+#include <stdint.h>
+
+//MSDN says in order to declare an interlocked function for use as an
+//intrinsic, include intrin.h and put the function in a #pragma intrinsic
+//directive.
+//The pragma appears to be unnecessary, but doesn't hurt.
+#pragma intrinsic(_InterlockedIncrement, _InterlockedExchangeAdd, _InterlockedDecrement)
+#pragma intrinsic(_InterlockedCompareExchange)
+
+static inline int32_t sk_atomic_inc(int32_t* addr) {
+ // InterlockedIncrement returns the new value, we want to return the old.
+ return _InterlockedIncrement(reinterpret_cast<long*>(addr)) - 1;
+}
+
+static inline int64_t sk_atomic_inc(int64_t* addr) {
+ // InterlockedIncrement returns the new value, we want to return the old.
+ return InterlockedIncrement64(addr) - 1;
+}
+
+static inline int32_t sk_atomic_add(int32_t* addr, int32_t inc) {
+ return _InterlockedExchangeAdd(reinterpret_cast<long*>(addr), static_cast<long>(inc));
+}
+
+static inline int32_t sk_atomic_dec(int32_t* addr) {
+ // InterlockedDecrement returns the new value, we want to return the old.
+ return _InterlockedDecrement(reinterpret_cast<long*>(addr)) + 1;
+}
+
+static inline void sk_membar_acquire__after_atomic_dec() { }
+
+static inline bool sk_atomic_cas(int32_t* addr, int32_t before, int32_t after) {
+ return _InterlockedCompareExchange(reinterpret_cast<long*>(addr), after, before) == before;
+}
+
+static inline void* sk_atomic_cas(void** addr, void* before, void* after) {
+ return InterlockedCompareExchangePointer(addr, after, before);
+}
+
+static inline void sk_membar_acquire__after_atomic_conditional_inc() { }
+
+#endif
diff --git a/include/ports/SkBarriers_arm.h b/include/ports/SkBarriers_arm.h
new file mode 100644
index 0000000000..386294e9b1
--- /dev/null
+++ b/include/ports/SkBarriers_arm.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkBarriers_arm_DEFINED
+#define SkBarriers_arm_DEFINED
+
+static inline void sk_compiler_barrier() { asm volatile("" : : : "memory"); }
+
+template <typename T>
+T sk_acquire_load(T* ptr) {
+ T val = *ptr;
+ __sync_synchronize(); // Issue a full barrier, which is an overkill acquire barrier.
+ return val;
+}
+
+template <typename T>
+T sk_consume_load(T* ptr) {
+ T val = *ptr;
+ // Unlike acquire, consume loads (data-dependent loads) are guaranteed not to reorder on ARM.
+ // No memory barrier is needed, so we just use a compiler barrier.
+ // C.f. http://preshing.com/20140709/the-purpose-of-memory_order_consume-in-cpp11/
+ sk_compiler_barrier();
+ return val;
+}
+
+template <typename T>
+void sk_release_store(T* ptr, T val) {
+ __sync_synchronize(); // Issue a full barrier, which is an overkill release barrier.
+ *ptr = val;
+}
+
+#endif//SkBarriers_x86_DEFINED
diff --git a/include/ports/SkBarriers_tsan.h b/include/ports/SkBarriers_tsan.h
new file mode 100644
index 0000000000..d72dbfd390
--- /dev/null
+++ b/include/ports/SkBarriers_tsan.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkBarriers_tsan_DEFINED
+#define SkBarriers_tsan_DEFINED
+
+static inline void sk_compiler_barrier() { asm volatile("" : : : "memory"); }
+
+template <typename T>
+T sk_acquire_load(T* ptr) {
+ SkASSERT(__atomic_always_lock_free(sizeof(T), ptr));
+ return __atomic_load_n(ptr, __ATOMIC_ACQUIRE);
+}
+
+template <typename T>
+T sk_consume_load(T* ptr) {
+ SkASSERT(__atomic_always_lock_free(sizeof(T), ptr));
+ return __atomic_load_n(ptr, __ATOMIC_CONSUME);
+}
+
+template <typename T>
+void sk_release_store(T* ptr, T val) {
+ SkASSERT(__atomic_always_lock_free(sizeof(T), ptr));
+ return __atomic_store_n(ptr, val, __ATOMIC_RELEASE);
+}
+
+#endif//SkBarriers_tsan_DEFINED
diff --git a/include/ports/SkBarriers_x86.h b/include/ports/SkBarriers_x86.h
new file mode 100644
index 0000000000..56e2658e97
--- /dev/null
+++ b/include/ports/SkBarriers_x86.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkBarriers_x86_DEFINED
+#define SkBarriers_x86_DEFINED
+
+#ifdef SK_BUILD_FOR_WIN
+# include <intrin.h>
+static inline void sk_compiler_barrier() { _ReadWriteBarrier(); }
+#else
+static inline void sk_compiler_barrier() { asm volatile("" : : : "memory"); }
+#endif
+
+template <typename T>
+T sk_acquire_load(T* ptr) {
+ T val = *ptr;
+ // On x86, all loads are acquire loads, so we only need a compiler barrier.
+ sk_compiler_barrier();
+ return val;
+}
+
+template <typename T>
+T sk_consume_load(T* ptr) {
+ // On x86, consume is the same as acquire, i.e. a normal load.
+ return sk_acquire_load(ptr);
+}
+
+template <typename T>
+void sk_release_store(T* ptr, T val) {
+ // On x86, all stores are release stores, so we only need a compiler barrier.
+ sk_compiler_barrier();
+ *ptr = val;
+}
+
+#endif//SkBarriers_x86_DEFINED
diff --git a/include/ports/SkMutex_pthread.h b/include/ports/SkMutex_pthread.h
new file mode 100644
index 0000000000..7452ece610
--- /dev/null
+++ b/include/ports/SkMutex_pthread.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkMutex_pthread_DEFINED
+#define SkMutex_pthread_DEFINED
+
+/** Posix pthread_mutex based mutex. */
+
+#include <errno.h>
+#include <pthread.h>
+
+// We use error-checking mutexes in Debug builds or normal fast mutexes in Release builds.
+// Debug builds get these checks for free:
+// - a double acquire() from the same thread fails immediately instead of deadlocking;
+// - release() checks that the mutex is being unlocked by its owner thread.
+// I don't see a built-in way to implement assertHeld(), so we track that with an fOwner field.
+
+// This isn't technically portable, but on Linux and Android pthread_t is some sort of int, and
+// on Darwin it's a pointer. So assuming pthread_self() never returns 0, it works as a sentinel.
+SkDEBUGCODE(static const pthread_t kNoOwner = 0;)
+
+// An SkBaseMutex is a POD structure that can be directly initialized at declaration time with
+// SK_DECLARE_STATIC_MUTEX. This avoids the generation of a static initializer in the final
+// machine code (and a corresponding static finalizer).
+struct SkBaseMutex {
+ void acquire() {
+ SkDEBUGCODE(int rc = ) pthread_mutex_lock(&fMutex);
+ SkASSERT(0 == rc);
+ SkDEBUGCODE(fOwner = pthread_self();)
+ }
+ void release() {
+ this->assertHeld(); // Usually redundant, but not for static mutexes on Macs (see below).
+ SkDEBUGCODE(fOwner = kNoOwner;)
+ SkDEBUGCODE(int rc = ) pthread_mutex_unlock(&fMutex);
+ SkASSERT(0 == rc);
+ }
+ void assertHeld() {
+ SkASSERT(0 != pthread_equal(fOwner, pthread_self()));
+ }
+
+ pthread_mutex_t fMutex;
+ SkDEBUGCODE(pthread_t fOwner;) // Read and write only when holding fMutex.
+};
+
+// A normal mutex that's required to be initialized through normal C++ construction,
+// i.e. when it's a member of another class, or allocated on the heap.
+class SkMutex : public SkBaseMutex {
+public:
+ SkMutex() {
+#ifdef SK_DEBUG
+ pthread_mutexattr_t attr;
+ SkASSERT(0 == pthread_mutexattr_init(&attr));
+ SkASSERT(0 == pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK));
+ SkASSERT(0 == pthread_mutex_init(&fMutex, &attr));
+ SkASSERT(0 == pthread_mutexattr_destroy(&attr));
+ fOwner = kNoOwner;
+#else
+ (void)pthread_mutex_init(&fMutex, NULL);
+#endif
+ }
+
+ ~SkMutex() {
+ SkDEBUGCODE(int rc = )pthread_mutex_destroy(&fMutex);
+ SkASSERT(0 == rc);
+ }
+
+private:
+ SkMutex(const SkMutex&);
+ SkMutex& operator=(const SkMutex&);
+};
+
+#if defined(SK_DEBUG) && defined(PTHREAD_ERRORCHECK_MUTEX_INITIALIZER)
+ // When possible we want to use error-check mutexes in Debug builds. See the note at the top.
+ #define SK_BASE_MUTEX_INIT { PTHREAD_ERRORCHECK_MUTEX_INITIALIZER, kNoOwner }
+#elif defined(SK_DEBUG)
+ // Macs don't support PTHREAD_ERRORCHECK_MUTEX_INITIALIZER when targeting <10.7. We target 10.6.
+ #define SK_BASE_MUTEX_INIT { PTHREAD_MUTEX_INITIALIZER, kNoOwner }
+#else
+ #define SK_BASE_MUTEX_INIT { PTHREAD_MUTEX_INITIALIZER }
+#endif
+
+// Using POD-style initialization prevents the generation of a static initializer.
+//
+// Without magic statics there are no thread safety guarantees on initialization
+// of local statics (even POD). As a result, it is illegal to use
+// SK_DECLARE_STATIC_MUTEX in a function.
+//
+// Because SkBaseMutex is not a primitive, a static SkBaseMutex cannot be
+// initialized in a class with this macro.
+#define SK_DECLARE_STATIC_MUTEX(name) namespace {} static SkBaseMutex name = SK_BASE_MUTEX_INIT
+
+#endif
diff --git a/include/ports/SkMutex_win.h b/include/ports/SkMutex_win.h
new file mode 100644
index 0000000000..fe06336a90
--- /dev/null
+++ b/include/ports/SkMutex_win.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkMutex_win_DEFINED
+#define SkMutex_win_DEFINED
+
+/** Windows CriticalSection based mutex. */
+
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# define WIN32_IS_MEAN_WAS_LOCALLY_DEFINED
+#endif
+#ifndef NOMINMAX
+# define NOMINMAX
+# define NOMINMAX_WAS_LOCALLY_DEFINED
+#endif
+#
+#include <windows.h>
+#
+#ifdef WIN32_IS_MEAN_WAS_LOCALLY_DEFINED
+# undef WIN32_IS_MEAN_WAS_LOCALLY_DEFINED
+# undef WIN32_LEAN_AND_MEAN
+#endif
+#ifdef NOMINMAX_WAS_LOCALLY_DEFINED
+# undef NOMINMAX_WAS_LOCALLY_DEFINED
+# undef NOMINMAX
+#endif
+
+// On Windows, SkBaseMutex and SkMutex are the same thing,
+// we can't easily get rid of static initializers. However,
+// we preserve the same inheritance pattern as other platforms
+// so that we can forward-declare cleanly.
+struct SkBaseMutex {
+public:
+ SkBaseMutex() {
+ InitializeCriticalSection(&fStorage);
+ SkDEBUGCODE(fOwner = 0;)
+ }
+
+ ~SkBaseMutex() {
+ SkASSERT(0 == fOwner);
+ DeleteCriticalSection(&fStorage);
+ }
+
+ void acquire() {
+ EnterCriticalSection(&fStorage);
+ SkDEBUGCODE(fOwner = GetCurrentThreadId();)
+ }
+
+ void release() {
+ this->assertHeld();
+ SkDEBUGCODE(fOwner = 0;)
+ LeaveCriticalSection(&fStorage);
+ }
+
+ void assertHeld() {
+ SkASSERT(GetCurrentThreadId() == fOwner);
+ }
+
+protected:
+ CRITICAL_SECTION fStorage;
+ SkDEBUGCODE(DWORD fOwner;)
+
+private:
+ SkBaseMutex(const SkBaseMutex&);
+ SkBaseMutex& operator=(const SkBaseMutex&);
+};
+
+class SkMutex : public SkBaseMutex { };
+
+// Windows currently provides no documented means of POD initializing a CRITICAL_SECTION.
+// As a result, it is illegal to SK_DECLARE_STATIC_MUTEX in a function.
+#define SK_DECLARE_STATIC_MUTEX(name) namespace{} static SkBaseMutex name
+
+#endif