Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(231)

Side by Side Diff: src/core/SkSharedMutex.cpp

Issue 1307863009: Add debug mode to shared mutex. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: fixed up Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« src/core/SkSharedMutex.h ('K') | « src/core/SkSharedMutex.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkSharedMutex.h" 8 #include "SkSharedMutex.h"
9 9
10 #include "SkAtomics.h" 10 #include "SkAtomics.h"
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
59 59
60 #else 60 #else
61 61
62 #define ANNOTATE_RWLOCK_CREATE(lock) 62 #define ANNOTATE_RWLOCK_CREATE(lock)
63 #define ANNOTATE_RWLOCK_DESTROY(lock) 63 #define ANNOTATE_RWLOCK_DESTROY(lock)
64 #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) 64 #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w)
65 #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) 65 #define ANNOTATE_RWLOCK_RELEASED(lock, is_w)
66 66
67 #endif 67 #endif
68 68
69 // The fQueueCounts fields holds many counts in an int32_t in order to make mana ging them atomic. 69 #ifdef SK_DEBUG
70 // These three counts must be the same size, so each gets 10 bits. The 10 bits r epresent 70
71 // the log of the count which is 1024. 71 SkSharedMutex::SkSharedMutex() { ANNOTATE_RWLOCK_CREATE(this); }
72 // 72 SkSharedMutex::~SkSharedMutex() { ANNOTATE_RWLOCK_DESTROY(this); }
73 // The three counts held in fQueueCounts are: 73 void SkSharedMutex::acquire() {
74 // * Shared - the number of shared lock holders currently running. 74 ThreadID threadID;
75 // * WaitingExclusive - the number of threads waiting for an exclusive lock. 75 int currentShardCount;
mtklein_C 2015/09/17 19:51:42 shard -> shared?
herb_g 2015/09/17 21:39:41 Done.
76 // * WaitingShared - the number of threads waiting to run while waiting for an e xclusive thread 76 int waitingExclusiveCount;
77 // to finish. 77 {
78 static const int kLogThreadCount = 10; 78 SkAutoMutexAcquire l(&fMu);
79 79
80 enum { 80 if (!fWaitingExclusive.tryAdd(threadID)) {
81 kSharedOffset = (0 * kLogThreadCount), 81 SkDebugf("Thread %lx already has an exclusive lock\n", threadID. toInt());
82 kWaitingExlusiveOffset = (1 * kLogThreadCount), 82 SkASSERT(false);
mtklein_C 2015/09/17 19:51:42 SkFAIL or SkDEBUGFAIL
herb_g 2015/09/17 21:39:41 Done.
83 kWaitingSharedOffset = (2 * kLogThreadCount), 83 }
84 kSharedMask = ((1 << kLogThreadCount) - 1) << kSharedOffset, 84
85 kWaitingExclusiveMask = ((1 << kLogThreadCount) - 1) << kWaitingExlusiveOff set, 85 currentShardCount = fCurrentShared.count();
86 kWaitingSharedMask = ((1 << kLogThreadCount) - 1) << kWaitingSharedOffse t, 86 waitingExclusiveCount = fWaitingExclusive.count();
87 }; 87 }
88 88
89 SkSharedMutex::SkSharedMutex() : fQueueCounts(0) { ANNOTATE_RWLOCK_CREATE(this); } 89 if (currentShardCount > 0 || waitingExclusiveCount > 1) {
90 SkSharedMutex::~SkSharedMutex() { ANNOTATE_RWLOCK_DESTROY(this); } 90 fExclusiveQueue.wait();
91 void SkSharedMutex::acquire() { 91 }
92 // Increment the count of exclusive queue waiters. 92
93 int32_t oldQueueCounts = fQueueCounts.fetch_add(1 << kWaitingExlusiveOffset, 93 ANNOTATE_RWLOCK_ACQUIRED(this, 1);
94 sk_memory_order_acquire); 94 }
95 95
96 // If there are no other exclusive waiters and no shared threads are running then run 96 // Implementation Detail:
97 // else wait. 97 // The shared threads need two seperate queues to keep the threads that were added after the
98 if ((oldQueueCounts & kWaitingExclusiveMask) > 0 || (oldQueueCounts & kShare dMask) > 0) { 98 // exclusive lock separate from the threads added before.
99 fExclusiveQueue.wait(); 99 void SkSharedMutex::release() {
100 } 100 ANNOTATE_RWLOCK_RELEASED(this, 1);
101 ANNOTATE_RWLOCK_ACQUIRED(this, 1); 101 ThreadID threadID;
102 } 102 int sharedWaitingCount;
103 103 int exclusiveWaitingCount;
104 void SkSharedMutex::release() { 104 int sharedQueueSelect;
105 ANNOTATE_RWLOCK_RELEASED(this, 1); 105 {
106 106 SkAutoMutexAcquire l(&fMu);
107 int32_t oldQueueCounts = fQueueCounts.load(sk_memory_order_relaxed); 107 SkASSERT(0 == fCurrentShared.count());
108 int32_t waitingShared; 108 if (!fWaitingExclusive.tryRemove(threadID)) {
109 int32_t newQueueCounts; 109 SkDebugf("Thread %lx did not have the lock held.\n", threadID.to Int());
mtklein_C 2015/09/17 19:51:42 ditto, etc.
herb_g 2015/09/17 21:39:41 Done.
110 do { 110 SkASSERT(false);
111 newQueueCounts = oldQueueCounts; 111 }
112 112 exclusiveWaitingCount = fWaitingExclusive.count();
113 // Decrement exclusive waiters. 113 sharedWaitingCount = fWaitingShared.count();
114 newQueueCounts -= 1 << kWaitingExlusiveOffset; 114 fWaitingShared.swap(fCurrentShared);
115 115 sharedQueueSelect = fSharedQueueSelect;
116 // The number of threads waiting to acquire a shared lock. 116 if (sharedWaitingCount > 0) {
117 waitingShared = (oldQueueCounts & kWaitingSharedMask) >> kWaitingSharedO ffset; 117 fSharedQueueSelect = 1 - fSharedQueueSelect;
118 118 }
119 // If there are any move the counts of all the shared waiters to actual shared. They are 119 }
120 // going to run next. 120
121 if (sharedWaitingCount > 0) {
122 fSharedQueue[sharedQueueSelect].signal(sharedWaitingCount);
123 } else if (exclusiveWaitingCount > 0) {
124 fExclusiveQueue.signal();
125 }
126 }
127
128 void SkSharedMutex::assertHeld() const {
129 ThreadID threadID;
130 SkAutoMutexAcquire l(&fMu);
131 SkASSERT(0 == fCurrentShared.count());
132 SkASSERT(fWaitingExclusive.find(threadID));
133 }
134
135 void SkSharedMutex::acquireShared() {
136 ThreadID threadID;
137 int exclusiveWaitingCount;
138 int sharedQueueSelect;
139 {
140 SkAutoMutexAcquire l(&fMu);
141 exclusiveWaitingCount = fWaitingExclusive.count();
142 if (exclusiveWaitingCount > 0) {
143 if (!fWaitingShared.tryAdd(threadID)) {
144 SkDebugf("Thread %lx was already waiting!\n", threadID.toInt ());
145 SkASSERT(false);
146 }
147 } else {
148 if (!fCurrentShared.tryAdd(threadID)) {
149 SkDebugf("Thread %lx already holds a shared lock!\n", thread ID.toInt());
150 SkASSERT(false);
151 }
152 }
153 sharedQueueSelect = fSharedQueueSelect;
154 }
155
156 if (exclusiveWaitingCount > 0) {
157 fSharedQueue[sharedQueueSelect].wait();
158 }
159
160 ANNOTATE_RWLOCK_ACQUIRED(this, 0);
161 }
162
163 void SkSharedMutex::releaseShared() {
164 ANNOTATE_RWLOCK_RELEASED(this, 0);
165 ThreadID threadID;
166
167 int currentSharedCount;
168 int waitingExclusiveCount;
169 {
170 SkAutoMutexAcquire l(&fMu);
171 if (!fCurrentShared.tryRemove(threadID)) {
172 SkDebugf("Thread %lx does not hold a shared lock.\n", threadID.t oInt());
173 SkASSERT(false);
174 }
175 currentSharedCount = fCurrentShared.count();
176 waitingExclusiveCount = fWaitingExclusive.count();
177 }
178
179 if (0 == currentSharedCount && waitingExclusiveCount > 0) {
180 fExclusiveQueue.signal();
181 }
182 }
183
184 void SkSharedMutex::assertHeldShared() const {
185 ThreadID threadID;
186 SkAutoMutexAcquire l(&fMu);
187 SkASSERT(fCurrentShared.find(threadID));
188 }
189
190 #else
191
192 // The fQueueCounts fields holds many counts in an int32_t in order to make managing them atomic.
193 // These three counts must be the same size, so each gets 10 bits. The 10 bi ts represent
194 // the log of the count which is 1024.
195 //
196 // The three counts held in fQueueCounts are:
197 // * Shared - the number of shared lock holders currently running.
198 // * WaitingExclusive - the number of threads waiting for an exclusive lock.
199 // * WaitingShared - the number of threads waiting to run while waiting for an exclusive thread
200 // to finish.
201 static const int kLogThreadCount = 10;
202
203 enum {
204 kSharedOffset = (0 * kLogThreadCount),
205 kWaitingExlusiveOffset = (1 * kLogThreadCount),
206 kWaitingSharedOffset = (2 * kLogThreadCount),
207 kSharedMask = ((1 << kLogThreadCount) - 1) << kSharedOffset,
208 kWaitingExclusiveMask = ((1 << kLogThreadCount) - 1) << kWaitingExlusiv eOffset,
209 kWaitingSharedMask = ((1 << kLogThreadCount) - 1) << kWaitingSharedO ffset,
210 };
211
212 SkSharedMutex::SkSharedMutex() : fQueueCounts(0) { ANNOTATE_RWLOCK_CREATE(th is); }
213 SkSharedMutex::~SkSharedMutex() { ANNOTATE_RWLOCK_DESTROY(this); }
214 void SkSharedMutex::acquire() {
215 // Increment the count of exclusive queue waiters.
216 int32_t oldQueueCounts = fQueueCounts.fetch_add(1 << kWaitingExlusiveOff set,
217 sk_memory_order_acquire) ;
218
219 // If there are no other exclusive waiters and no shared threads are run ning then run
220 // else wait.
221 if ((oldQueueCounts & kWaitingExclusiveMask) > 0 || (oldQueueCounts & kS haredMask) > 0) {
222 fExclusiveQueue.wait();
223 }
224 ANNOTATE_RWLOCK_ACQUIRED(this, 1);
225 }
226
227 void SkSharedMutex::release() {
228 ANNOTATE_RWLOCK_RELEASED(this, 1);
229
230 int32_t oldQueueCounts = fQueueCounts.load(sk_memory_order_relaxed);
231 int32_t waitingShared;
232 int32_t newQueueCounts;
233 do {
234 newQueueCounts = oldQueueCounts;
235
236 // Decrement exclusive waiters.
237 newQueueCounts -= 1 << kWaitingExlusiveOffset;
238
239 // The number of threads waiting to acquire a shared lock.
240 waitingShared = (oldQueueCounts & kWaitingSharedMask) >> kWaitingSha redOffset;
241
242 // If there are any move the counts of all the shared waiters to act ual shared. They are
243 // going to run next.
244 if (waitingShared > 0) {
245
246 // Set waiting shared to zero.
247 newQueueCounts &= ~kWaitingSharedMask;
248
249 // Because this is the exclusive release, then there are zero re aders. So, the bits
250 // for shared locks should be zero. Since those bits are zero, w e can just |= in the
251 // waitingShared count instead of clearing with an &= and then | = the count.
252 newQueueCounts |= waitingShared << kSharedOffset;
253 }
254
255 } while (!fQueueCounts.compare_exchange(&oldQueueCounts, newQueueCounts,
256 sk_memory_order_release, sk_memo ry_order_relaxed));
257
121 if (waitingShared > 0) { 258 if (waitingShared > 0) {
122 259 // Run all the shared.
123 // Set waiting shared to zero. 260 fSharedQueue.signal(waitingShared);
124 newQueueCounts &= ~kWaitingSharedMask; 261 } else if ((newQueueCounts & kWaitingExclusiveMask) > 0) {
125 262 // Run a single exclusive waiter.
126 // Because this is the exclusive release, then there are zero reader s. So, the bits 263 fExclusiveQueue.signal();
127 // for shared locks should be zero. Since those bits are zero, we ca n just |= in the 264 }
128 // waitingShared count instead of clearing with an &= and then |= th e count. 265 }
129 newQueueCounts |= waitingShared << kSharedOffset; 266
130 } 267 void SkSharedMutex::acquireShared() {
131 268 int32_t oldQueueCounts = fQueueCounts.load(sk_memory_order_relaxed);
132 } while (!fQueueCounts.compare_exchange(&oldQueueCounts, newQueueCounts, 269 int32_t newQueueCounts;
133 sk_memory_order_release, sk_memory_o rder_relaxed)); 270 do {
134 271 newQueueCounts = oldQueueCounts;
135 if (waitingShared > 0) { 272 // If there are waiting exclusives then this shared lock waits else it runs.
136 // Run all the shared. 273 if ((newQueueCounts & kWaitingExclusiveMask) > 0) {
137 fSharedQueue.signal(waitingShared); 274 newQueueCounts += 1 << kWaitingSharedOffset;
138 } else if ((newQueueCounts & kWaitingExclusiveMask) > 0) { 275 } else {
139 // Run a single exclusive waiter. 276 newQueueCounts += 1 << kSharedOffset;
140 fExclusiveQueue.signal(); 277 }
141 } 278 } while (!fQueueCounts.compare_exchange(&oldQueueCounts, newQueueCounts,
142 } 279 sk_memory_order_acquire, sk_memo ry_order_relaxed));
143 280
144 #ifdef SK_DEBUG 281 // If there are waiting exclusives, then this shared waits until after i t runs.
145 void SkSharedMutex::assertHeld() const { 282 if ((newQueueCounts & kWaitingExclusiveMask) > 0) {
146 int32_t queueCounts = fQueueCounts.load(sk_memory_order_relaxed); 283 fSharedQueue.wait();
147 // These are very loose asserts about the mutex being held exclusively. 284 }
148 SkASSERTF(0 == (queueCounts & kSharedMask), 285 ANNOTATE_RWLOCK_ACQUIRED(this, 0);
149 "running shared: %d, exclusive: %d, waiting shared: %d", 286
150 (queueCounts & kSharedMask) >> kSharedOffset, 287 }
151 (queueCounts & kWaitingExclusiveMask) >> kWaitingExlusiveOffset, 288
152 (queueCounts & kWaitingSharedMask) >> kWaitingSharedOffset); 289 void SkSharedMutex::releaseShared() {
153 SkASSERTF((queueCounts & kWaitingExclusiveMask) > 0, 290 ANNOTATE_RWLOCK_RELEASED(this, 0);
154 "running shared: %d, exclusive: %d, waiting shared: %d", 291
155 (queueCounts & kSharedMask) >> kSharedOffset, 292 // Decrement the shared count.
156 (queueCounts & kWaitingExclusiveMask) >> kWaitingExlusiveOffset, 293 int32_t oldQueueCounts = fQueueCounts.fetch_sub(1 << kSharedOffset,
157 (queueCounts & kWaitingSharedMask) >> kWaitingSharedOffset); 294 sk_memory_order_release) ;
158 } 295
296 // If shared count is going to zero (because the old count == 1) and the re are exclusive
297 // waiters, then run a single exclusive waiter.
298 if (((oldQueueCounts & kSharedMask) >> kSharedOffset) == 1
299 && (oldQueueCounts & kWaitingExclusiveMask) > 0) {
300 fExclusiveQueue.signal();
301 }
302 }
303
159 #endif 304 #endif
160
161 void SkSharedMutex::acquireShared() {
162 int32_t oldQueueCounts = fQueueCounts.load(sk_memory_order_relaxed);
163 int32_t newQueueCounts;
164 do {
165 newQueueCounts = oldQueueCounts;
166 // If there are waiting exclusives then this shared lock waits else it r uns.
167 if ((newQueueCounts & kWaitingExclusiveMask) > 0) {
168 newQueueCounts += 1 << kWaitingSharedOffset;
169 } else {
170 newQueueCounts += 1 << kSharedOffset;
171 }
172 } while (!fQueueCounts.compare_exchange(&oldQueueCounts, newQueueCounts,
173 sk_memory_order_acquire, sk_memory_o rder_relaxed));
174
175 // If there are waiting exclusives, then this shared waits until after it ru ns.
176 if ((newQueueCounts & kWaitingExclusiveMask) > 0) {
177 fSharedQueue.wait();
178 }
179 ANNOTATE_RWLOCK_ACQUIRED(this, 0);
180
181 }
182
183 void SkSharedMutex::releaseShared() {
184 ANNOTATE_RWLOCK_RELEASED(this, 0);
185
186 // Decrement the shared count.
187 int32_t oldQueueCounts = fQueueCounts.fetch_sub(1 << kSharedOffset,
188 sk_memory_order_release);
189
190 // If shared count is going to zero (because the old count == 1) and there a re exclusive
191 // waiters, then run a single exclusive waiter.
192 if (((oldQueueCounts & kSharedMask) >> kSharedOffset) == 1
193 && (oldQueueCounts & kWaitingExclusiveMask) > 0) {
194 fExclusiveQueue.signal();
195 }
196 }
197
198 #ifdef SK_DEBUG
199 void SkSharedMutex::assertHeldShared() const {
200 int32_t queueCounts = fQueueCounts.load(sk_memory_order_relaxed);
201 // A very loose assert about the mutex being shared.
202 SkASSERTF((queueCounts & kSharedMask) > 0,
203 "running shared: %d, exclusive: %d, waiting shared: %d",
204 (queueCounts & kSharedMask) >> kSharedOffset,
205 (queueCounts & kWaitingExclusiveMask) >> kWaitingExlusiveOffset,
206 (queueCounts & kWaitingSharedMask) >> kWaitingSharedOffset);
207 }
208
209 #endif
OLDNEW
« src/core/SkSharedMutex.h ('K') | « src/core/SkSharedMutex.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698