xref: /aosp_15_r20/external/angle/src/libANGLE/ContextMutex.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2023 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker // ContextMutex.cpp: Classes for protecting Context access and EGLImage siblings.
7*8975f5c5SAndroid Build Coastguard Worker 
8*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/ContextMutex.h"
9*8975f5c5SAndroid Build Coastguard Worker 
10*8975f5c5SAndroid Build Coastguard Worker #include "common/system_utils.h"
11*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Context.h"
12*8975f5c5SAndroid Build Coastguard Worker 
13*8975f5c5SAndroid Build Coastguard Worker namespace egl
14*8975f5c5SAndroid Build Coastguard Worker {
15*8975f5c5SAndroid Build Coastguard Worker 
16*8975f5c5SAndroid Build Coastguard Worker namespace
17*8975f5c5SAndroid Build Coastguard Worker {
CheckThreadIdCurrent(const std::atomic<angle::ThreadId> & threadId,angle::ThreadId * currentThreadIdOut)18*8975f5c5SAndroid Build Coastguard Worker [[maybe_unused]] bool CheckThreadIdCurrent(const std::atomic<angle::ThreadId> &threadId,
19*8975f5c5SAndroid Build Coastguard Worker                                            angle::ThreadId *currentThreadIdOut)
20*8975f5c5SAndroid Build Coastguard Worker {
21*8975f5c5SAndroid Build Coastguard Worker     *currentThreadIdOut = angle::GetCurrentThreadId();
22*8975f5c5SAndroid Build Coastguard Worker     return (threadId.load(std::memory_order_relaxed) == *currentThreadIdOut);
23*8975f5c5SAndroid Build Coastguard Worker }
24*8975f5c5SAndroid Build Coastguard Worker 
TryUpdateThreadId(std::atomic<angle::ThreadId> * threadId,angle::ThreadId oldThreadId,angle::ThreadId newThreadId)25*8975f5c5SAndroid Build Coastguard Worker [[maybe_unused]] bool TryUpdateThreadId(std::atomic<angle::ThreadId> *threadId,
26*8975f5c5SAndroid Build Coastguard Worker                                         angle::ThreadId oldThreadId,
27*8975f5c5SAndroid Build Coastguard Worker                                         angle::ThreadId newThreadId)
28*8975f5c5SAndroid Build Coastguard Worker {
29*8975f5c5SAndroid Build Coastguard Worker     const bool ok = (threadId->load(std::memory_order_relaxed) == oldThreadId);
30*8975f5c5SAndroid Build Coastguard Worker     if (ok)
31*8975f5c5SAndroid Build Coastguard Worker     {
32*8975f5c5SAndroid Build Coastguard Worker         threadId->store(newThreadId, std::memory_order_relaxed);
33*8975f5c5SAndroid Build Coastguard Worker     }
34*8975f5c5SAndroid Build Coastguard Worker     return ok;
35*8975f5c5SAndroid Build Coastguard Worker }
36*8975f5c5SAndroid Build Coastguard Worker }  // namespace
37*8975f5c5SAndroid Build Coastguard Worker 
38*8975f5c5SAndroid Build Coastguard Worker // ScopedContextMutexAddRefLock
lock(ContextMutex * mutex)39*8975f5c5SAndroid Build Coastguard Worker void ScopedContextMutexAddRefLock::lock(ContextMutex *mutex)
40*8975f5c5SAndroid Build Coastguard Worker {
41*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mutex != nullptr);
42*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mMutex == nullptr);
43*8975f5c5SAndroid Build Coastguard Worker     // lock() before addRef() - using mMutex as synchronization
44*8975f5c5SAndroid Build Coastguard Worker     mutex->lock();
45*8975f5c5SAndroid Build Coastguard Worker     // Take the "root" mutex after the lock.
46*8975f5c5SAndroid Build Coastguard Worker     mMutex = mutex->getRoot();
47*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mMutex->isReferenced());
48*8975f5c5SAndroid Build Coastguard Worker     mMutex->addRef();
49*8975f5c5SAndroid Build Coastguard Worker }
50*8975f5c5SAndroid Build Coastguard Worker 
51*8975f5c5SAndroid Build Coastguard Worker // ContextMutex
ContextMutex(ContextMutex * root)52*8975f5c5SAndroid Build Coastguard Worker ContextMutex::ContextMutex(ContextMutex *root)
53*8975f5c5SAndroid Build Coastguard Worker     : mRoot(this), mOwnerThreadId(angle::InvalidThreadId()), mLockLevel(0), mRefCount(0), mRank(0)
54*8975f5c5SAndroid Build Coastguard Worker {
55*8975f5c5SAndroid Build Coastguard Worker     if (root != nullptr)
56*8975f5c5SAndroid Build Coastguard Worker     {
57*8975f5c5SAndroid Build Coastguard Worker         setNewRoot(root);
58*8975f5c5SAndroid Build Coastguard Worker     }
59*8975f5c5SAndroid Build Coastguard Worker }
60*8975f5c5SAndroid Build Coastguard Worker 
~ContextMutex()61*8975f5c5SAndroid Build Coastguard Worker ContextMutex::~ContextMutex()
62*8975f5c5SAndroid Build Coastguard Worker {
63*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mLockLevel == 0);
64*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mRefCount == 0);
65*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mLeaves.empty());
66*8975f5c5SAndroid Build Coastguard Worker 
67*8975f5c5SAndroid Build Coastguard Worker     ContextMutex *const root = getRoot();
68*8975f5c5SAndroid Build Coastguard Worker     if (this == root)
69*8975f5c5SAndroid Build Coastguard Worker     {
70*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mOldRoots.empty());
71*8975f5c5SAndroid Build Coastguard Worker     }
72*8975f5c5SAndroid Build Coastguard Worker     else
73*8975f5c5SAndroid Build Coastguard Worker     {
74*8975f5c5SAndroid Build Coastguard Worker         for (ContextMutex *oldRoot : mOldRoots)
75*8975f5c5SAndroid Build Coastguard Worker         {
76*8975f5c5SAndroid Build Coastguard Worker             ASSERT(oldRoot->getRoot() == root);
77*8975f5c5SAndroid Build Coastguard Worker             ASSERT(oldRoot->mLeaves.empty());
78*8975f5c5SAndroid Build Coastguard Worker             oldRoot->release();
79*8975f5c5SAndroid Build Coastguard Worker         }
80*8975f5c5SAndroid Build Coastguard Worker         root->removeLeaf(this);
81*8975f5c5SAndroid Build Coastguard Worker         root->release();
82*8975f5c5SAndroid Build Coastguard Worker     }
83*8975f5c5SAndroid Build Coastguard Worker }
84*8975f5c5SAndroid Build Coastguard Worker 
Merge(ContextMutex * lockedMutex,ContextMutex * otherMutex)85*8975f5c5SAndroid Build Coastguard Worker void ContextMutex::Merge(ContextMutex *lockedMutex, ContextMutex *otherMutex)
86*8975f5c5SAndroid Build Coastguard Worker {
87*8975f5c5SAndroid Build Coastguard Worker     ASSERT(lockedMutex != nullptr);
88*8975f5c5SAndroid Build Coastguard Worker     ASSERT(otherMutex != nullptr);
89*8975f5c5SAndroid Build Coastguard Worker 
90*8975f5c5SAndroid Build Coastguard Worker     // Since lockedMutex is locked, its "root" pointer is stable.
91*8975f5c5SAndroid Build Coastguard Worker     ContextMutex *lockedRoot      = lockedMutex->getRoot();
92*8975f5c5SAndroid Build Coastguard Worker     ContextMutex *otherLockedRoot = nullptr;
93*8975f5c5SAndroid Build Coastguard Worker 
94*8975f5c5SAndroid Build Coastguard Worker     // Mutex merging will update the structure of both mutexes, therefore both mutexes must be
95*8975f5c5SAndroid Build Coastguard Worker     // locked before continuing. First mutex is already locked, need to lock the other mutex.
96*8975f5c5SAndroid Build Coastguard Worker     // Because other thread may perform merge with same mutexes reversed, we can't simply lock
97*8975f5c5SAndroid Build Coastguard Worker     // otherMutex - this may cause a deadlock. Additionally, otherMutex may have same "root" (same
98*8975f5c5SAndroid Build Coastguard Worker     // mutex or already merged), not only merging is unnecessary, but locking otherMutex will
99*8975f5c5SAndroid Build Coastguard Worker     // guarantee a deadlock.
100*8975f5c5SAndroid Build Coastguard Worker 
101*8975f5c5SAndroid Build Coastguard Worker     for (;;)
102*8975f5c5SAndroid Build Coastguard Worker     {
103*8975f5c5SAndroid Build Coastguard Worker         // First, check that "root" of otherMutex is the same as "root" of lockedMutex.
104*8975f5c5SAndroid Build Coastguard Worker         // lockedRoot is stable by definition and it is safe to compare with "unstable root".
105*8975f5c5SAndroid Build Coastguard Worker         ContextMutex *otherRoot = otherMutex->getRoot();
106*8975f5c5SAndroid Build Coastguard Worker         if (otherRoot == lockedRoot)
107*8975f5c5SAndroid Build Coastguard Worker         {
108*8975f5c5SAndroid Build Coastguard Worker             // Do nothing if two mutexes are the same/merged.
109*8975f5c5SAndroid Build Coastguard Worker             return;
110*8975f5c5SAndroid Build Coastguard Worker         }
111*8975f5c5SAndroid Build Coastguard Worker         // Second, try to lock otherMutex "root" (can't use lock()/lockImpl(), see above comment).
112*8975f5c5SAndroid Build Coastguard Worker         if (otherRoot->tryLockImpl())
113*8975f5c5SAndroid Build Coastguard Worker         {
114*8975f5c5SAndroid Build Coastguard Worker             otherLockedRoot = otherRoot->getRoot();
115*8975f5c5SAndroid Build Coastguard Worker             // otherMutex "root" can't become lockedMutex "root". For that to happen, lockedMutex
116*8975f5c5SAndroid Build Coastguard Worker             // must be locked from some other thread first, which is impossible, since it is already
117*8975f5c5SAndroid Build Coastguard Worker             // locked by this thread.
118*8975f5c5SAndroid Build Coastguard Worker             ASSERT(otherLockedRoot != lockedRoot);
119*8975f5c5SAndroid Build Coastguard Worker             // Lock is successful. Both mutexes are locked - can proceed with the merge...
120*8975f5c5SAndroid Build Coastguard Worker             break;
121*8975f5c5SAndroid Build Coastguard Worker         }
122*8975f5c5SAndroid Build Coastguard Worker         // Lock was unsuccessful - unlock and retry...
123*8975f5c5SAndroid Build Coastguard Worker         // May use "unlockImpl()" because lockedRoot is a "stable root" mutex.
124*8975f5c5SAndroid Build Coastguard Worker         // Note: lock will be preserved in case of the recursive lock.
125*8975f5c5SAndroid Build Coastguard Worker         lockedRoot->unlockImpl();
126*8975f5c5SAndroid Build Coastguard Worker         // Sleep random amount to allow one of the thread acquire the lock next time...
127*8975f5c5SAndroid Build Coastguard Worker         std::this_thread::sleep_for(std::chrono::microseconds(rand() % 91 + 10));
128*8975f5c5SAndroid Build Coastguard Worker         // Because lockedMutex was unlocked, its "root" might have been changed. Below line will
129*8975f5c5SAndroid Build Coastguard Worker         // reacquire the lock and update lockedRoot pointer.
130*8975f5c5SAndroid Build Coastguard Worker         lockedMutex->lock();
131*8975f5c5SAndroid Build Coastguard Worker         lockedRoot = lockedMutex->getRoot();
132*8975f5c5SAndroid Build Coastguard Worker     }
133*8975f5c5SAndroid Build Coastguard Worker 
134*8975f5c5SAndroid Build Coastguard Worker     // Decide the new "root". See mRank comment for more details...
135*8975f5c5SAndroid Build Coastguard Worker 
136*8975f5c5SAndroid Build Coastguard Worker     ContextMutex *oldRoot = otherLockedRoot;
137*8975f5c5SAndroid Build Coastguard Worker     ContextMutex *newRoot = lockedRoot;
138*8975f5c5SAndroid Build Coastguard Worker 
139*8975f5c5SAndroid Build Coastguard Worker     if (oldRoot->mRank > newRoot->mRank)
140*8975f5c5SAndroid Build Coastguard Worker     {
141*8975f5c5SAndroid Build Coastguard Worker         std::swap(oldRoot, newRoot);
142*8975f5c5SAndroid Build Coastguard Worker     }
143*8975f5c5SAndroid Build Coastguard Worker     else if (oldRoot->mRank == newRoot->mRank)
144*8975f5c5SAndroid Build Coastguard Worker     {
145*8975f5c5SAndroid Build Coastguard Worker         ++newRoot->mRank;
146*8975f5c5SAndroid Build Coastguard Worker     }
147*8975f5c5SAndroid Build Coastguard Worker 
148*8975f5c5SAndroid Build Coastguard Worker     ASSERT(newRoot->isReferenced());
149*8975f5c5SAndroid Build Coastguard Worker 
150*8975f5c5SAndroid Build Coastguard Worker     // Update the structure
151*8975f5c5SAndroid Build Coastguard Worker     for (ContextMutex *const leaf : oldRoot->mLeaves)
152*8975f5c5SAndroid Build Coastguard Worker     {
153*8975f5c5SAndroid Build Coastguard Worker         ASSERT(leaf->getRoot() == oldRoot);
154*8975f5c5SAndroid Build Coastguard Worker         leaf->setNewRoot(newRoot);
155*8975f5c5SAndroid Build Coastguard Worker     }
156*8975f5c5SAndroid Build Coastguard Worker     oldRoot->mLeaves.clear();
157*8975f5c5SAndroid Build Coastguard Worker     oldRoot->setNewRoot(newRoot);
158*8975f5c5SAndroid Build Coastguard Worker 
159*8975f5c5SAndroid Build Coastguard Worker     // Leave only the "merged" mutex locked. "oldRoot" already merged, need to use "unlockImpl()"
160*8975f5c5SAndroid Build Coastguard Worker     oldRoot->unlockImpl();
161*8975f5c5SAndroid Build Coastguard Worker 
162*8975f5c5SAndroid Build Coastguard Worker     // Merge from recursive lock is unexpected. Handle such cases anyway to be safe.
163*8975f5c5SAndroid Build Coastguard Worker     while (oldRoot->mLockLevel > 0)
164*8975f5c5SAndroid Build Coastguard Worker     {
165*8975f5c5SAndroid Build Coastguard Worker         newRoot->lockImpl();
166*8975f5c5SAndroid Build Coastguard Worker         oldRoot->unlockImpl();
167*8975f5c5SAndroid Build Coastguard Worker     }
168*8975f5c5SAndroid Build Coastguard Worker }
169*8975f5c5SAndroid Build Coastguard Worker 
setNewRoot(ContextMutex * newRoot)170*8975f5c5SAndroid Build Coastguard Worker void ContextMutex::setNewRoot(ContextMutex *newRoot)
171*8975f5c5SAndroid Build Coastguard Worker {
172*8975f5c5SAndroid Build Coastguard Worker     ContextMutex *const oldRoot = getRoot();
173*8975f5c5SAndroid Build Coastguard Worker 
174*8975f5c5SAndroid Build Coastguard Worker     ASSERT(newRoot != oldRoot);
175*8975f5c5SAndroid Build Coastguard Worker     mRoot.store(newRoot, std::memory_order_relaxed);
176*8975f5c5SAndroid Build Coastguard Worker     newRoot->addRef();
177*8975f5c5SAndroid Build Coastguard Worker 
178*8975f5c5SAndroid Build Coastguard Worker     newRoot->addLeaf(this);
179*8975f5c5SAndroid Build Coastguard Worker 
180*8975f5c5SAndroid Build Coastguard Worker     if (oldRoot != this)
181*8975f5c5SAndroid Build Coastguard Worker     {
182*8975f5c5SAndroid Build Coastguard Worker         mOldRoots.emplace_back(oldRoot);
183*8975f5c5SAndroid Build Coastguard Worker     }
184*8975f5c5SAndroid Build Coastguard Worker }
185*8975f5c5SAndroid Build Coastguard Worker 
addLeaf(ContextMutex * leaf)186*8975f5c5SAndroid Build Coastguard Worker void ContextMutex::addLeaf(ContextMutex *leaf)
187*8975f5c5SAndroid Build Coastguard Worker {
188*8975f5c5SAndroid Build Coastguard Worker     ASSERT(this == getRoot());
189*8975f5c5SAndroid Build Coastguard Worker     ASSERT(leaf->getRoot() == this);
190*8975f5c5SAndroid Build Coastguard Worker     ASSERT(leaf->mLeaves.empty());
191*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mLeaves.count(leaf) == 0);
192*8975f5c5SAndroid Build Coastguard Worker     mLeaves.emplace(leaf);
193*8975f5c5SAndroid Build Coastguard Worker }
194*8975f5c5SAndroid Build Coastguard Worker 
removeLeaf(ContextMutex * leaf)195*8975f5c5SAndroid Build Coastguard Worker void ContextMutex::removeLeaf(ContextMutex *leaf)
196*8975f5c5SAndroid Build Coastguard Worker {
197*8975f5c5SAndroid Build Coastguard Worker     ASSERT(this == getRoot());
198*8975f5c5SAndroid Build Coastguard Worker     ASSERT(leaf->getRoot() == this);
199*8975f5c5SAndroid Build Coastguard Worker     ASSERT(leaf->mLeaves.empty());
200*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mLeaves.count(leaf) == 1);
201*8975f5c5SAndroid Build Coastguard Worker     mLeaves.erase(leaf);
202*8975f5c5SAndroid Build Coastguard Worker }
203*8975f5c5SAndroid Build Coastguard Worker 
release(UnlockBehaviour unlockBehaviour)204*8975f5c5SAndroid Build Coastguard Worker void ContextMutex::release(UnlockBehaviour unlockBehaviour)
205*8975f5c5SAndroid Build Coastguard Worker {
206*8975f5c5SAndroid Build Coastguard Worker     ASSERT(isReferenced());
207*8975f5c5SAndroid Build Coastguard Worker     const bool needDelete = (--mRefCount == 0);
208*8975f5c5SAndroid Build Coastguard Worker     if (unlockBehaviour == UnlockBehaviour::kUnlock)
209*8975f5c5SAndroid Build Coastguard Worker     {
210*8975f5c5SAndroid Build Coastguard Worker         ASSERT(this == getRoot());
211*8975f5c5SAndroid Build Coastguard Worker         unlockImpl();
212*8975f5c5SAndroid Build Coastguard Worker     }
213*8975f5c5SAndroid Build Coastguard Worker     if (needDelete)
214*8975f5c5SAndroid Build Coastguard Worker     {
215*8975f5c5SAndroid Build Coastguard Worker         delete this;
216*8975f5c5SAndroid Build Coastguard Worker     }
217*8975f5c5SAndroid Build Coastguard Worker }
218*8975f5c5SAndroid Build Coastguard Worker 
try_lock()219*8975f5c5SAndroid Build Coastguard Worker bool ContextMutex::try_lock()
220*8975f5c5SAndroid Build Coastguard Worker {
221*8975f5c5SAndroid Build Coastguard Worker     return getRoot()->tryLockImpl();
222*8975f5c5SAndroid Build Coastguard Worker }
223*8975f5c5SAndroid Build Coastguard Worker 
lock()224*8975f5c5SAndroid Build Coastguard Worker void ContextMutex::lock()
225*8975f5c5SAndroid Build Coastguard Worker {
226*8975f5c5SAndroid Build Coastguard Worker     getRoot()->lockImpl();
227*8975f5c5SAndroid Build Coastguard Worker }
228*8975f5c5SAndroid Build Coastguard Worker 
unlock()229*8975f5c5SAndroid Build Coastguard Worker void ContextMutex::unlock()
230*8975f5c5SAndroid Build Coastguard Worker {
231*8975f5c5SAndroid Build Coastguard Worker     ContextMutex *const root = getRoot();
232*8975f5c5SAndroid Build Coastguard Worker     // "root" is currently locked so "root->getRoot()" will return stable result.
233*8975f5c5SAndroid Build Coastguard Worker     ASSERT(root == root->getRoot());
234*8975f5c5SAndroid Build Coastguard Worker     root->unlockImpl();
235*8975f5c5SAndroid Build Coastguard Worker }
236*8975f5c5SAndroid Build Coastguard Worker 
237*8975f5c5SAndroid Build Coastguard Worker #if defined(ANGLE_ENABLE_CONTEXT_MUTEX_RECURSION)
tryLockImpl()238*8975f5c5SAndroid Build Coastguard Worker bool ContextMutex::tryLockImpl()
239*8975f5c5SAndroid Build Coastguard Worker {
240*8975f5c5SAndroid Build Coastguard Worker     const angle::ThreadId threadId = angle::GetCurrentThreadId();
241*8975f5c5SAndroid Build Coastguard Worker     if (ANGLE_UNLIKELY(!mMutex.try_lock()))
242*8975f5c5SAndroid Build Coastguard Worker     {
243*8975f5c5SAndroid Build Coastguard Worker         if (ANGLE_UNLIKELY(mOwnerThreadId.load(std::memory_order_relaxed) == threadId))
244*8975f5c5SAndroid Build Coastguard Worker         {
245*8975f5c5SAndroid Build Coastguard Worker             ASSERT(this == getRoot());
246*8975f5c5SAndroid Build Coastguard Worker             ASSERT(mLockLevel > 0);
247*8975f5c5SAndroid Build Coastguard Worker             ++mLockLevel;
248*8975f5c5SAndroid Build Coastguard Worker             return true;
249*8975f5c5SAndroid Build Coastguard Worker         }
250*8975f5c5SAndroid Build Coastguard Worker         return false;
251*8975f5c5SAndroid Build Coastguard Worker     }
252*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mOwnerThreadId.load(std::memory_order_relaxed) == angle::InvalidThreadId());
253*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mLockLevel == 0);
254*8975f5c5SAndroid Build Coastguard Worker     ContextMutex *const root = getRoot();
255*8975f5c5SAndroid Build Coastguard Worker     if (ANGLE_UNLIKELY(this != root))
256*8975f5c5SAndroid Build Coastguard Worker     {
257*8975f5c5SAndroid Build Coastguard Worker         // Unlock, so only the "stable root" mutex remains locked
258*8975f5c5SAndroid Build Coastguard Worker         mMutex.unlock();
259*8975f5c5SAndroid Build Coastguard Worker         return root->tryLockImpl();
260*8975f5c5SAndroid Build Coastguard Worker     }
261*8975f5c5SAndroid Build Coastguard Worker     mOwnerThreadId.store(threadId, std::memory_order_relaxed);
262*8975f5c5SAndroid Build Coastguard Worker     mLockLevel = 1;
263*8975f5c5SAndroid Build Coastguard Worker     return true;
264*8975f5c5SAndroid Build Coastguard Worker }
265*8975f5c5SAndroid Build Coastguard Worker 
lockImpl()266*8975f5c5SAndroid Build Coastguard Worker void ContextMutex::lockImpl()
267*8975f5c5SAndroid Build Coastguard Worker {
268*8975f5c5SAndroid Build Coastguard Worker     const angle::ThreadId threadId = angle::GetCurrentThreadId();
269*8975f5c5SAndroid Build Coastguard Worker     if (ANGLE_UNLIKELY(!mMutex.try_lock()))
270*8975f5c5SAndroid Build Coastguard Worker     {
271*8975f5c5SAndroid Build Coastguard Worker         if (ANGLE_UNLIKELY(mOwnerThreadId.load(std::memory_order_relaxed) == threadId))
272*8975f5c5SAndroid Build Coastguard Worker         {
273*8975f5c5SAndroid Build Coastguard Worker             ASSERT(this == getRoot());
274*8975f5c5SAndroid Build Coastguard Worker             ASSERT(mLockLevel > 0);
275*8975f5c5SAndroid Build Coastguard Worker             ++mLockLevel;
276*8975f5c5SAndroid Build Coastguard Worker             return;
277*8975f5c5SAndroid Build Coastguard Worker         }
278*8975f5c5SAndroid Build Coastguard Worker         mMutex.lock();
279*8975f5c5SAndroid Build Coastguard Worker     }
280*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mOwnerThreadId.load(std::memory_order_relaxed) == angle::InvalidThreadId());
281*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mLockLevel == 0);
282*8975f5c5SAndroid Build Coastguard Worker     ContextMutex *const root = getRoot();
283*8975f5c5SAndroid Build Coastguard Worker     if (ANGLE_UNLIKELY(this != root))
284*8975f5c5SAndroid Build Coastguard Worker     {
285*8975f5c5SAndroid Build Coastguard Worker         // Unlock, so only the "stable root" mutex remains locked
286*8975f5c5SAndroid Build Coastguard Worker         mMutex.unlock();
287*8975f5c5SAndroid Build Coastguard Worker         root->lockImpl();
288*8975f5c5SAndroid Build Coastguard Worker     }
289*8975f5c5SAndroid Build Coastguard Worker     else
290*8975f5c5SAndroid Build Coastguard Worker     {
291*8975f5c5SAndroid Build Coastguard Worker         mOwnerThreadId.store(threadId, std::memory_order_relaxed);
292*8975f5c5SAndroid Build Coastguard Worker         mLockLevel = 1;
293*8975f5c5SAndroid Build Coastguard Worker     }
294*8975f5c5SAndroid Build Coastguard Worker }
295*8975f5c5SAndroid Build Coastguard Worker 
unlockImpl()296*8975f5c5SAndroid Build Coastguard Worker void ContextMutex::unlockImpl()
297*8975f5c5SAndroid Build Coastguard Worker {
298*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mOwnerThreadId.load(std::memory_order_relaxed) == angle::GetCurrentThreadId());
299*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mLockLevel > 0);
300*8975f5c5SAndroid Build Coastguard Worker     if (ANGLE_LIKELY(--mLockLevel == 0))
301*8975f5c5SAndroid Build Coastguard Worker     {
302*8975f5c5SAndroid Build Coastguard Worker         mOwnerThreadId.store(angle::InvalidThreadId(), std::memory_order_relaxed);
303*8975f5c5SAndroid Build Coastguard Worker         mMutex.unlock();
304*8975f5c5SAndroid Build Coastguard Worker     }
305*8975f5c5SAndroid Build Coastguard Worker }
306*8975f5c5SAndroid Build Coastguard Worker #else
tryLockImpl()307*8975f5c5SAndroid Build Coastguard Worker bool ContextMutex::tryLockImpl()
308*8975f5c5SAndroid Build Coastguard Worker {
309*8975f5c5SAndroid Build Coastguard Worker     angle::ThreadId currentThreadId;
310*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!CheckThreadIdCurrent(mOwnerThreadId, &currentThreadId));
311*8975f5c5SAndroid Build Coastguard Worker     if (mMutex.try_lock())
312*8975f5c5SAndroid Build Coastguard Worker     {
313*8975f5c5SAndroid Build Coastguard Worker         ContextMutex *const root = getRoot();
314*8975f5c5SAndroid Build Coastguard Worker         if (ANGLE_UNLIKELY(this != root))
315*8975f5c5SAndroid Build Coastguard Worker         {
316*8975f5c5SAndroid Build Coastguard Worker             // Unlock, so only the "stable root" mutex remains locked
317*8975f5c5SAndroid Build Coastguard Worker             mMutex.unlock();
318*8975f5c5SAndroid Build Coastguard Worker             return root->tryLockImpl();
319*8975f5c5SAndroid Build Coastguard Worker         }
320*8975f5c5SAndroid Build Coastguard Worker         ASSERT(TryUpdateThreadId(&mOwnerThreadId, angle::InvalidThreadId(), currentThreadId));
321*8975f5c5SAndroid Build Coastguard Worker         return true;
322*8975f5c5SAndroid Build Coastguard Worker     }
323*8975f5c5SAndroid Build Coastguard Worker     return false;
324*8975f5c5SAndroid Build Coastguard Worker }
325*8975f5c5SAndroid Build Coastguard Worker 
lockImpl()326*8975f5c5SAndroid Build Coastguard Worker void ContextMutex::lockImpl()
327*8975f5c5SAndroid Build Coastguard Worker {
328*8975f5c5SAndroid Build Coastguard Worker     angle::ThreadId currentThreadId;
329*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!CheckThreadIdCurrent(mOwnerThreadId, &currentThreadId));
330*8975f5c5SAndroid Build Coastguard Worker     mMutex.lock();
331*8975f5c5SAndroid Build Coastguard Worker     ContextMutex *const root = getRoot();
332*8975f5c5SAndroid Build Coastguard Worker     if (ANGLE_UNLIKELY(this != root))
333*8975f5c5SAndroid Build Coastguard Worker     {
334*8975f5c5SAndroid Build Coastguard Worker         // Unlock, so only the "stable root" mutex remains locked
335*8975f5c5SAndroid Build Coastguard Worker         mMutex.unlock();
336*8975f5c5SAndroid Build Coastguard Worker         root->lockImpl();
337*8975f5c5SAndroid Build Coastguard Worker     }
338*8975f5c5SAndroid Build Coastguard Worker     else
339*8975f5c5SAndroid Build Coastguard Worker     {
340*8975f5c5SAndroid Build Coastguard Worker         ASSERT(TryUpdateThreadId(&mOwnerThreadId, angle::InvalidThreadId(), currentThreadId));
341*8975f5c5SAndroid Build Coastguard Worker     }
342*8975f5c5SAndroid Build Coastguard Worker }
343*8975f5c5SAndroid Build Coastguard Worker 
unlockImpl()344*8975f5c5SAndroid Build Coastguard Worker void ContextMutex::unlockImpl()
345*8975f5c5SAndroid Build Coastguard Worker {
346*8975f5c5SAndroid Build Coastguard Worker     ASSERT(
347*8975f5c5SAndroid Build Coastguard Worker         TryUpdateThreadId(&mOwnerThreadId, angle::GetCurrentThreadId(), angle::InvalidThreadId()));
348*8975f5c5SAndroid Build Coastguard Worker     mMutex.unlock();
349*8975f5c5SAndroid Build Coastguard Worker }
350*8975f5c5SAndroid Build Coastguard Worker #endif
351*8975f5c5SAndroid Build Coastguard Worker 
352*8975f5c5SAndroid Build Coastguard Worker }  // namespace egl
353