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