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