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 "SkMacros.h" 12 #include "SkSemaphore.h" 13 #include "SkTypes.h" 14 #include <atomic> 15 16 #ifdef SK_DEBUG 17 #include "SkMutex.h" 18 #include <memory> 19 #endif // SK_DEBUG 20 21 // There are two shared lock implementations one debug the other is high performance. They implement 22 // an interface similar to pthread's rwlocks. 23 // This is a shared lock implementation similar to pthreads rwlocks. The high performance 24 // implementation is cribbed from Preshing's article: 25 // http://preshing.com/20150316/semaphores-are-surprisingly-versatile/ 26 // 27 // This lock does not obey strict queue ordering. It will always alternate between readers and 28 // a single writer. 29 class SkSharedMutex { 30 public: 31 SkSharedMutex(); 32 ~SkSharedMutex(); 33 // Acquire lock for exclusive use. 34 void acquire(); 35 36 // Release lock for exclusive use. 37 void release(); 38 39 // Fail if exclusive is not held. 40 void assertHeld() const; 41 42 // Acquire lock for shared use. 43 void acquireShared(); 44 45 // Release lock for shared use. 46 void releaseShared(); 47 48 // Fail if shared lock not held. 49 void assertHeldShared() const; 50 51 private: 52 #ifdef SK_DEBUG 53 class ThreadIDSet; 54 std::unique_ptr<ThreadIDSet> fCurrentShared; 55 std::unique_ptr<ThreadIDSet> fWaitingExclusive; 56 std::unique_ptr<ThreadIDSet> fWaitingShared; 57 int fSharedQueueSelect{0}; 58 mutable SkMutex fMu; 59 SkSemaphore fSharedQueue[2]; 60 SkSemaphore fExclusiveQueue; 61 #else 62 std::atomic<int32_t> fQueueCounts; 63 SkSemaphore fSharedQueue; 64 SkSemaphore fExclusiveQueue; 65 #endif // SK_DEBUG 66 }; 67 68 #ifndef SK_DEBUG assertHeld()69inline void SkSharedMutex::assertHeld() const {}; assertHeldShared()70inline void SkSharedMutex::assertHeldShared() const {}; 71 #endif // SK_DEBUG 72 73 class SkAutoSharedMutexShared { 74 public: SkAutoSharedMutexShared(SkSharedMutex & lock)75 SkAutoSharedMutexShared(SkSharedMutex& lock) : fLock(lock) { lock.acquireShared(); } ~SkAutoSharedMutexShared()76 ~SkAutoSharedMutexShared() { fLock.releaseShared(); } 77 private: 78 SkSharedMutex& fLock; 79 }; 80 81 #define SkAutoSharedMutexShared(...) SK_REQUIRE_LOCAL_VAR(SkAutoSharedMutexShared) 82 83 #endif // SkSharedLock_DEFINED 84