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 #include "SkSharedMutex.h" 9 10 #include "SkAtomics.h" 11 #include "SkTypes.h" 12 #include "SkSemaphore.h" 13 14 #if !defined(__has_feature) 15 #define __has_feature(x) 0 16 #endif 17 18 #if __has_feature(thread_sanitizer) 19 20 /* Report that a lock has been created at address "lock". */ 21 #define ANNOTATE_RWLOCK_CREATE(lock) \ 22 AnnotateRWLockCreate(__FILE__, __LINE__, lock) 23 24 /* Report that the lock at address "lock" is about to be destroyed. */ 25 #define ANNOTATE_RWLOCK_DESTROY(lock) \ 26 AnnotateRWLockDestroy(__FILE__, __LINE__, lock) 27 28 /* Report that the lock at address "lock" has been acquired. 29 is_w=1 for writer lock, is_w=0 for reader lock. */ 30 #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \ 31 AnnotateRWLockAcquired(__FILE__, __LINE__, lock, is_w) 32 33 /* Report that the lock at address "lock" is about to be released. */ 34 #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \ 35 AnnotateRWLockReleased(__FILE__, __LINE__, lock, is_w) 36 37 #if defined(DYNAMIC_ANNOTATIONS_WANT_ATTRIBUTE_WEAK) 38 #if defined(__GNUC__) 39 #define DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK __attribute__((weak)) 40 #else 41 /* TODO(glider): for Windows support we may want to change this macro in order 42 to prepend __declspec(selectany) to the annotations' declarations. */ 43 #error weak annotations are not supported for your compiler 44 #endif 45 #else 46 #define DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK 47 #endif 48 49 extern "C" { 50 void AnnotateRWLockCreate( 51 const char *file, int line, 52 const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; 53 void AnnotateRWLockDestroy( 54 const char *file, int line, 55 const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; 56 void AnnotateRWLockAcquired( 57 const char *file, int line, 58 const volatile void *lock, long is_w) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; 59 void AnnotateRWLockReleased( 60 const char *file, int line, 61 const volatile void *lock, long is_w) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; 62 } 63 64 #else 65 66 #define ANNOTATE_RWLOCK_CREATE(lock) 67 #define ANNOTATE_RWLOCK_DESTROY(lock) 68 #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) 69 #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) 70 71 #endif 72 73 #ifdef SK_DEBUG 74 75 #include "SkThreadID.h" 76 #include "SkTDArray.h" 77 78 class SkSharedMutex::ThreadIDSet { 79 public: 80 // Returns true if threadID is in the set. find(SkThreadID threadID) const81 bool find(SkThreadID threadID) const { 82 for (auto& t : fThreadIDs) { 83 if (t == threadID) return true; 84 } 85 return false; 86 } 87 88 // Returns true if did not already exist. tryAdd(SkThreadID threadID)89 bool tryAdd(SkThreadID threadID) { 90 for (auto& t : fThreadIDs) { 91 if (t == threadID) return false; 92 } 93 fThreadIDs.append(1, &threadID); 94 return true; 95 } 96 // Returns true if already exists in Set. tryRemove(SkThreadID threadID)97 bool tryRemove(SkThreadID threadID) { 98 for (int i = 0; i < fThreadIDs.count(); ++i) { 99 if (fThreadIDs[i] == threadID) { 100 fThreadIDs.remove(i); 101 return true; 102 } 103 } 104 return false; 105 } 106 swap(ThreadIDSet & other)107 void swap(ThreadIDSet& other) { 108 fThreadIDs.swap(other.fThreadIDs); 109 } 110 count() const111 int count() const { 112 return fThreadIDs.count(); 113 } 114 115 private: 116 SkTDArray<SkThreadID> fThreadIDs; 117 }; 118 SkSharedMutex()119 SkSharedMutex::SkSharedMutex() 120 : fCurrentShared(new ThreadIDSet) 121 , fWaitingExclusive(new ThreadIDSet) 122 , fWaitingShared(new ThreadIDSet){ 123 ANNOTATE_RWLOCK_CREATE(this); 124 } 125 ~SkSharedMutex()126 SkSharedMutex::~SkSharedMutex() { ANNOTATE_RWLOCK_DESTROY(this); } 127 acquire()128 void SkSharedMutex::acquire() { 129 SkThreadID threadID(SkGetThreadID()); 130 int currentSharedCount; 131 int waitingExclusiveCount; 132 { 133 SkAutoMutexAcquire l(&fMu); 134 135 if (!fWaitingExclusive->tryAdd(threadID)) { 136 SkDEBUGFAILF("Thread %lx already has an exclusive lock\n", threadID); 137 } 138 139 currentSharedCount = fCurrentShared->count(); 140 waitingExclusiveCount = fWaitingExclusive->count(); 141 } 142 143 if (currentSharedCount > 0 || waitingExclusiveCount > 1) { 144 fExclusiveQueue.wait(); 145 } 146 147 ANNOTATE_RWLOCK_ACQUIRED(this, 1); 148 } 149 150 // Implementation Detail: 151 // The shared threads need two seperate queues to keep the threads that were added after the 152 // exclusive lock separate from the threads added before. release()153 void SkSharedMutex::release() { 154 ANNOTATE_RWLOCK_RELEASED(this, 1); 155 SkThreadID threadID(SkGetThreadID()); 156 int sharedWaitingCount; 157 int exclusiveWaitingCount; 158 int sharedQueueSelect; 159 { 160 SkAutoMutexAcquire l(&fMu); 161 SkASSERT(0 == fCurrentShared->count()); 162 if (!fWaitingExclusive->tryRemove(threadID)) { 163 SkDEBUGFAILF("Thread %lx did not have the lock held.\n", threadID); 164 } 165 exclusiveWaitingCount = fWaitingExclusive->count(); 166 sharedWaitingCount = fWaitingShared->count(); 167 fWaitingShared.swap(fCurrentShared); 168 sharedQueueSelect = fSharedQueueSelect; 169 if (sharedWaitingCount > 0) { 170 fSharedQueueSelect = 1 - fSharedQueueSelect; 171 } 172 } 173 174 if (sharedWaitingCount > 0) { 175 fSharedQueue[sharedQueueSelect].signal(sharedWaitingCount); 176 } else if (exclusiveWaitingCount > 0) { 177 fExclusiveQueue.signal(); 178 } 179 } 180 assertHeld() const181 void SkSharedMutex::assertHeld() const { 182 SkThreadID threadID(SkGetThreadID()); 183 SkAutoMutexAcquire l(&fMu); 184 SkASSERT(0 == fCurrentShared->count()); 185 SkASSERT(fWaitingExclusive->find(threadID)); 186 } 187 acquireShared()188 void SkSharedMutex::acquireShared() { 189 SkThreadID threadID(SkGetThreadID()); 190 int exclusiveWaitingCount; 191 int sharedQueueSelect; 192 { 193 SkAutoMutexAcquire l(&fMu); 194 exclusiveWaitingCount = fWaitingExclusive->count(); 195 if (exclusiveWaitingCount > 0) { 196 if (!fWaitingShared->tryAdd(threadID)) { 197 SkDEBUGFAILF("Thread %lx was already waiting!\n", threadID); 198 } 199 } else { 200 if (!fCurrentShared->tryAdd(threadID)) { 201 SkDEBUGFAILF("Thread %lx already holds a shared lock!\n", threadID); 202 } 203 } 204 sharedQueueSelect = fSharedQueueSelect; 205 } 206 207 if (exclusiveWaitingCount > 0) { 208 fSharedQueue[sharedQueueSelect].wait(); 209 } 210 211 ANNOTATE_RWLOCK_ACQUIRED(this, 0); 212 } 213 releaseShared()214 void SkSharedMutex::releaseShared() { 215 ANNOTATE_RWLOCK_RELEASED(this, 0); 216 SkThreadID threadID(SkGetThreadID()); 217 218 int currentSharedCount; 219 int waitingExclusiveCount; 220 { 221 SkAutoMutexAcquire l(&fMu); 222 if (!fCurrentShared->tryRemove(threadID)) { 223 SkDEBUGFAILF("Thread %lx does not hold a shared lock.\n", threadID); 224 } 225 currentSharedCount = fCurrentShared->count(); 226 waitingExclusiveCount = fWaitingExclusive->count(); 227 } 228 229 if (0 == currentSharedCount && waitingExclusiveCount > 0) { 230 fExclusiveQueue.signal(); 231 } 232 } 233 assertHeldShared() const234 void SkSharedMutex::assertHeldShared() const { 235 SkThreadID threadID(SkGetThreadID()); 236 SkAutoMutexAcquire l(&fMu); 237 SkASSERT(fCurrentShared->find(threadID)); 238 } 239 240 #else 241 242 // The fQueueCounts fields holds many counts in an int32_t in order to make managing them atomic. 243 // These three counts must be the same size, so each gets 10 bits. The 10 bits represent 244 // the log of the count which is 1024. 245 // 246 // The three counts held in fQueueCounts are: 247 // * Shared - the number of shared lock holders currently running. 248 // * WaitingExclusive - the number of threads waiting for an exclusive lock. 249 // * WaitingShared - the number of threads waiting to run while waiting for an exclusive thread 250 // to finish. 251 static const int kLogThreadCount = 10; 252 253 enum { 254 kSharedOffset = (0 * kLogThreadCount), 255 kWaitingExlusiveOffset = (1 * kLogThreadCount), 256 kWaitingSharedOffset = (2 * kLogThreadCount), 257 kSharedMask = ((1 << kLogThreadCount) - 1) << kSharedOffset, 258 kWaitingExclusiveMask = ((1 << kLogThreadCount) - 1) << kWaitingExlusiveOffset, 259 kWaitingSharedMask = ((1 << kLogThreadCount) - 1) << kWaitingSharedOffset, 260 }; 261 SkSharedMutex()262 SkSharedMutex::SkSharedMutex() : fQueueCounts(0) { ANNOTATE_RWLOCK_CREATE(this); } ~SkSharedMutex()263 SkSharedMutex::~SkSharedMutex() { ANNOTATE_RWLOCK_DESTROY(this); } acquire()264 void SkSharedMutex::acquire() { 265 // Increment the count of exclusive queue waiters. 266 int32_t oldQueueCounts = fQueueCounts.fetch_add(1 << kWaitingExlusiveOffset, 267 sk_memory_order_acquire); 268 269 // If there are no other exclusive waiters and no shared threads are running then run 270 // else wait. 271 if ((oldQueueCounts & kWaitingExclusiveMask) > 0 || (oldQueueCounts & kSharedMask) > 0) { 272 fExclusiveQueue.wait(); 273 } 274 ANNOTATE_RWLOCK_ACQUIRED(this, 1); 275 } 276 release()277 void SkSharedMutex::release() { 278 ANNOTATE_RWLOCK_RELEASED(this, 1); 279 280 int32_t oldQueueCounts = fQueueCounts.load(sk_memory_order_relaxed); 281 int32_t waitingShared; 282 int32_t newQueueCounts; 283 do { 284 newQueueCounts = oldQueueCounts; 285 286 // Decrement exclusive waiters. 287 newQueueCounts -= 1 << kWaitingExlusiveOffset; 288 289 // The number of threads waiting to acquire a shared lock. 290 waitingShared = (oldQueueCounts & kWaitingSharedMask) >> kWaitingSharedOffset; 291 292 // If there are any move the counts of all the shared waiters to actual shared. They are 293 // going to run next. 294 if (waitingShared > 0) { 295 296 // Set waiting shared to zero. 297 newQueueCounts &= ~kWaitingSharedMask; 298 299 // Because this is the exclusive release, then there are zero readers. So, the bits 300 // for shared locks should be zero. Since those bits are zero, we can just |= in the 301 // waitingShared count instead of clearing with an &= and then |= the count. 302 newQueueCounts |= waitingShared << kSharedOffset; 303 } 304 305 } while (!fQueueCounts.compare_exchange(&oldQueueCounts, newQueueCounts, 306 sk_memory_order_release, sk_memory_order_relaxed)); 307 308 if (waitingShared > 0) { 309 // Run all the shared. 310 fSharedQueue.signal(waitingShared); 311 } else if ((newQueueCounts & kWaitingExclusiveMask) > 0) { 312 // Run a single exclusive waiter. 313 fExclusiveQueue.signal(); 314 } 315 } 316 acquireShared()317 void SkSharedMutex::acquireShared() { 318 int32_t oldQueueCounts = fQueueCounts.load(sk_memory_order_relaxed); 319 int32_t newQueueCounts; 320 do { 321 newQueueCounts = oldQueueCounts; 322 // If there are waiting exclusives then this shared lock waits else it runs. 323 if ((newQueueCounts & kWaitingExclusiveMask) > 0) { 324 newQueueCounts += 1 << kWaitingSharedOffset; 325 } else { 326 newQueueCounts += 1 << kSharedOffset; 327 } 328 } while (!fQueueCounts.compare_exchange(&oldQueueCounts, newQueueCounts, 329 sk_memory_order_acquire, sk_memory_order_relaxed)); 330 331 // If there are waiting exclusives, then this shared waits until after it runs. 332 if ((newQueueCounts & kWaitingExclusiveMask) > 0) { 333 fSharedQueue.wait(); 334 } 335 ANNOTATE_RWLOCK_ACQUIRED(this, 0); 336 337 } 338 releaseShared()339 void SkSharedMutex::releaseShared() { 340 ANNOTATE_RWLOCK_RELEASED(this, 0); 341 342 // Decrement the shared count. 343 int32_t oldQueueCounts = fQueueCounts.fetch_sub(1 << kSharedOffset, 344 sk_memory_order_release); 345 346 // If shared count is going to zero (because the old count == 1) and there are exclusive 347 // waiters, then run a single exclusive waiter. 348 if (((oldQueueCounts & kSharedMask) >> kSharedOffset) == 1 349 && (oldQueueCounts & kWaitingExclusiveMask) > 0) { 350 fExclusiveQueue.signal(); 351 } 352 } 353 354 #endif 355