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. 28class SkSharedMutex { 29public: 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 50private: 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 68inline void SkSharedMutex::assertHeld() const {}; 69inline void SkSharedMutex::assertHeldShared() const {}; 70#endif // SK_DEBUG 71 72class SkAutoSharedMutexShared { 73public: 74 SkAutoSharedMutexShared(SkSharedMutex& lock) : fLock(lock) { lock.acquireShared(); } 75 ~SkAutoSharedMutexShared() { fLock.releaseShared(); } 76private: 77 SkSharedMutex& fLock; 78}; 79 80#define SkAutoSharedMutexShared(...) SK_REQUIRE_LOCAL_VAR(SkAutoSharedMutexShared) 81 82#endif // SkSharedLock_DEFINED 83