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