1 /* 2 * Copyright 2015 Google Inc. 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 #ifndef SkMutex_DEFINED 9 #define SkMutex_DEFINED 10 11 // This file is not part of the public Skia API. 12 #include "../private/SkSemaphore.h" 13 #include "SkTypes.h" 14 15 #ifdef SK_DEBUG 16 #include "../private/SkThreadID.h" 17 #endif 18 19 #define SK_MUTEX_SEMAPHORE_INIT {1, {0}} 20 21 #ifdef SK_DEBUG 22 #define SK_BASE_MUTEX_INIT {SK_MUTEX_SEMAPHORE_INIT, 0} 23 #else 24 #define SK_BASE_MUTEX_INIT {SK_MUTEX_SEMAPHORE_INIT} 25 #endif 26 27 // Using POD-style initialization prevents the generation of a static initializer. 28 // 29 // Without magic statics there are no thread safety guarantees on initialization 30 // of local statics (even POD). As a result, it is illegal to use 31 // SK_DECLARE_STATIC_MUTEX in a function. 32 // 33 // Because SkBaseMutex is not a primitive, a static SkBaseMutex cannot be 34 // initialized in a class with this macro. 35 #define SK_DECLARE_STATIC_MUTEX(name) namespace {} static SkBaseMutex name = SK_BASE_MUTEX_INIT; 36 37 struct SkBaseMutex { 38 void acquire() { 39 fSemaphore.wait(); 40 SkDEBUGCODE(fOwner = SkGetThreadID();) 41 } 42 43 void release() { 44 this->assertHeld(); 45 SkDEBUGCODE(fOwner = kIllegalThreadID;) 46 fSemaphore.signal(); 47 } 48 49 void assertHeld() { 50 SkASSERT(fOwner == SkGetThreadID()); 51 } 52 53 SkBaseSemaphore fSemaphore; 54 SkDEBUGCODE(SkThreadID fOwner;) 55 }; 56 57 // This needs to use subclassing instead of encapsulation to make SkAutoMutexAcquire to work. 58 class SkMutex : public SkBaseMutex { 59 public: 60 SkMutex () { 61 fSemaphore = SK_MUTEX_SEMAPHORE_INIT; 62 SkDEBUGCODE(fOwner = kIllegalThreadID); 63 } 64 ~SkMutex () { fSemaphore.deleteSemaphore(); } 65 SkMutex(const SkMutex&) = delete; 66 SkMutex& operator=(const SkMutex&) = delete; 67 }; 68 69 template <typename Lock> 70 class SkAutoTAcquire : SkNoncopyable { 71 public: 72 explicit SkAutoTAcquire(Lock& mutex) : fMutex(&mutex) { 73 SkASSERT(fMutex != nullptr); 74 mutex.acquire(); 75 } 76 77 explicit SkAutoTAcquire(Lock* mutex) : fMutex(mutex) { 78 if (mutex) { 79 mutex->acquire(); 80 } 81 } 82 83 /** If the mutex has not been released, release it now. */ 84 ~SkAutoTAcquire() { 85 if (fMutex) { 86 fMutex->release(); 87 } 88 } 89 90 /** If the mutex has not been released, release it now. */ 91 void release() { 92 if (fMutex) { 93 fMutex->release(); 94 fMutex = nullptr; 95 } 96 } 97 98 /** Assert that we're holding the mutex. */ 99 void assertHeld() { 100 SkASSERT(fMutex); 101 fMutex->assertHeld(); 102 } 103 104 private: 105 Lock* fMutex; 106 }; 107 108 // SkAutoTExclusive is a lighter weight version of SkAutoTAcquire. It assumes that there is a valid 109 // mutex, thus removing the check for the null pointer. 110 template <typename Lock> 111 class SkAutoTExclusive { 112 public: 113 SkAutoTExclusive(Lock& lock) : fLock(lock) { lock.acquire(); } 114 ~SkAutoTExclusive() { fLock.release(); } 115 private: 116 Lock &fLock; 117 }; 118 119 typedef SkAutoTAcquire<SkBaseMutex> SkAutoMutexAcquire; 120 #define SkAutoMutexAcquire(...) SK_REQUIRE_LOCAL_VAR(SkAutoMutexAcquire) 121 122 typedef SkAutoTExclusive<SkBaseMutex> SkAutoMutexExclusive; 123 #define SkAutoMutexExclusive(...) SK_REQUIRE_LOCAL_VAR(SkAutoMutexExclusive) 124 125 #endif//SkMutex_DEFINED 126