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 SkSharedLock_DEFINED 9 #define SkSharedLock_DEFINED 10 11 #include "include/private/base/SkDebug.h" 12 #include "include/private/base/SkSemaphore.h" 13 #include "include/private/base/SkThreadAnnotations.h" 14 15 #ifdef SK_DEBUG 16 #include "include/private/base/SkMutex.h" 17 #include <memory> 18 #endif // SK_DEBUG 19 20 // There are two shared lock implementations one debug the other is high performance. They implement 21 // an interface similar to pthread's rwlocks. 22 // This is a shared lock implementation similar to pthreads rwlocks. The high performance 23 // implementation is cribbed from Preshing's article: 24 // http://preshing.com/20150316/semaphores-are-surprisingly-versatile/ 25 // 26 // This lock does not obey strict queue ordering. It will always alternate between readers and 27 // a single writer. 28 class SK_CAPABILITY("mutex") SkSharedMutex { 29 public: 30 SkSharedMutex(); 31 ~SkSharedMutex(); 32 // Acquire lock for exclusive use. 33 void acquire() SK_ACQUIRE(); 34 35 // Release lock for exclusive use. 36 void release() SK_RELEASE_CAPABILITY(); 37 38 // Fail if exclusive is not held. 39 void assertHeld() const SK_ASSERT_CAPABILITY(this); 40 41 // Acquire lock for shared use. 42 void acquireShared() SK_ACQUIRE_SHARED(); 43 44 // Release lock for shared use. 45 void releaseShared() SK_RELEASE_SHARED_CAPABILITY(); 46 47 // Fail if shared lock not held. 48 void assertHeldShared() const SK_ASSERT_SHARED_CAPABILITY(this); 49 50 private: 51 #ifdef SK_DEBUG 52 class ThreadIDSet; 53 std::unique_ptr<ThreadIDSet> fCurrentShared; 54 std::unique_ptr<ThreadIDSet> fWaitingExclusive; 55 std::unique_ptr<ThreadIDSet> fWaitingShared; 56 int fSharedQueueSelect{0}; 57 mutable SkMutex fMu; 58 SkSemaphore fSharedQueue[2]; 59 SkSemaphore fExclusiveQueue; 60 #else 61 std::atomic<int32_t> fQueueCounts; 62 SkSemaphore fSharedQueue; 63 SkSemaphore fExclusiveQueue; 64 #endif // SK_DEBUG 65 }; 66 67 #ifndef SK_DEBUG assertHeld()68inline void SkSharedMutex::assertHeld() const {} assertHeldShared()69inline void SkSharedMutex::assertHeldShared() const {} 70 #endif // SK_DEBUG 71 72 class SK_SCOPED_CAPABILITY SkAutoSharedMutexExclusive { 73 public: SkAutoSharedMutexExclusive(SkSharedMutex & lock)74 explicit SkAutoSharedMutexExclusive(SkSharedMutex& lock) SK_ACQUIRE(lock) 75 : fLock(lock) { 76 lock.acquire(); 77 } SK_RELEASE_CAPABILITY()78 ~SkAutoSharedMutexExclusive() SK_RELEASE_CAPABILITY() { fLock.release(); } 79 80 private: 81 SkSharedMutex& fLock; 82 }; 83 84 class SK_SCOPED_CAPABILITY SkAutoSharedMutexShared { 85 public: SkAutoSharedMutexShared(SkSharedMutex & lock)86 explicit SkAutoSharedMutexShared(SkSharedMutex& lock) SK_ACQUIRE_SHARED(lock) 87 : fLock(lock) { 88 lock.acquireShared(); 89 } 90 91 // You would think this should be SK_RELEASE_SHARED_CAPABILITY, but SK_SCOPED_CAPABILITY 92 // doesn't fully understand the difference between shared and exclusive. 93 // Please review https://reviews.llvm.org/D52578 for more information. SK_RELEASE_CAPABILITY()94 ~SkAutoSharedMutexShared() SK_RELEASE_CAPABILITY() { fLock.releaseShared(); } 95 96 private: 97 SkSharedMutex& fLock; 98 }; 99 100 #endif // SkSharedLock_DEFINED 101