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