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 "SkAtomics.h" 12 #include "SkSemaphore.h" 13 #include "SkTypes.h" 14 15 #ifdef SK_DEBUG 16 #include "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 SkSharedMutex { 29 public: 30 SkSharedMutex(); 31 ~SkSharedMutex(); 32 // Acquire lock for exclusive use. 33 void acquire(); 34 35 // Release lock for exclusive use. 36 void release(); 37 38 // Fail if exclusive is not held. 39 void assertHeld() const; 40 41 // Acquire lock for shared use. 42 void acquireShared(); 43 44 // Release lock for shared use. 45 void releaseShared(); 46 47 // Fail if shared lock not held. 48 void assertHeldShared() const; 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 SkAtomic<int32_t> fQueueCounts; 62 SkSemaphore fSharedQueue; 63 SkSemaphore fExclusiveQueue; 64 #endif // SK_DEBUG 65 }; 66 67 #ifndef SK_DEBUG 68 inline void SkSharedMutex::assertHeld() const {}; 69 inline void SkSharedMutex::assertHeldShared() const {}; 70 #endif // SK_DEBUG 71 72 class SkAutoSharedMutexShared { 73 public: 74 SkAutoSharedMutexShared(SkSharedMutex& lock) : fLock(lock) { lock.acquireShared(); } 75 ~SkAutoSharedMutexShared() { fLock.releaseShared(); } 76 private: 77 SkSharedMutex& fLock; 78 }; 79 80 #define SkAutoSharedMutexShared(...) SK_REQUIRE_LOCAL_VAR(SkAutoSharedMutexShared) 81 82 #endif // SkSharedLock_DEFINED 83