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