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/SkMacros.h" 13#include "include/private/SkSemaphore.h" 14#include "include/private/SkThreadAnnotations.h" 15#include <atomic> 16 17#ifdef SK_DEBUG 18 #include "include/private/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. 30class SK_CAPABILITY("mutex") SkSharedMutex { 31public: 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 52private: 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 70inline void SkSharedMutex::assertHeld() const {}; 71inline void SkSharedMutex::assertHeldShared() const {}; 72#endif // SK_DEBUG 73 74class SK_SCOPED_CAPABILITY SkAutoSharedMutexExclusive { 75public: 76 explicit SkAutoSharedMutexExclusive(SkSharedMutex& lock) SK_ACQUIRE(lock) 77 : fLock(lock) { 78 lock.acquire(); 79 } 80 ~SkAutoSharedMutexExclusive() SK_RELEASE_CAPABILITY() { fLock.release(); } 81 82private: 83 SkSharedMutex& fLock; 84}; 85 86class SK_SCOPED_CAPABILITY SkAutoSharedMutexShared { 87public: 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. 96 ~SkAutoSharedMutexShared() SK_RELEASE_CAPABILITY() { fLock.releaseShared(); } 97 98private: 99 SkSharedMutex& fLock; 100}; 101 102#endif // SkSharedLock_DEFINED 103