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