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 {
acquireSkBaseMutex38     void acquire() {
39         fSemaphore.wait();
40         SkDEBUGCODE(fOwner = SkGetThreadID();)
41     }
42 
releaseSkBaseMutex43     void release() {
44         this->assertHeld();
45         SkDEBUGCODE(fOwner = kIllegalThreadID;)
46         fSemaphore.signal();
47     }
48 
assertHeldSkBaseMutex49     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:
SkMutex()60     SkMutex () {
61         fSemaphore = SK_MUTEX_SEMAPHORE_INIT;
62         SkDEBUGCODE(fOwner = kIllegalThreadID);
63     }
~SkMutex()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:
SkAutoTAcquire(Lock & mutex)72     explicit SkAutoTAcquire(Lock& mutex) : fMutex(&mutex) {
73         SkASSERT(fMutex != nullptr);
74         mutex.acquire();
75     }
76 
SkAutoTAcquire(Lock * mutex)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. */
~SkAutoTAcquire()84     ~SkAutoTAcquire() {
85         if (fMutex) {
86             fMutex->release();
87         }
88     }
89 
90     /** If the mutex has not been released, release it now. */
release()91     void release() {
92         if (fMutex) {
93             fMutex->release();
94             fMutex = nullptr;
95         }
96     }
97 
98     /** Assert that we're holding the mutex. */
assertHeld()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:
SkAutoTExclusive(Lock & lock)113     SkAutoTExclusive(Lock& lock) : fLock(lock) { lock.acquire(); }
~SkAutoTExclusive()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