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, ¤tThreadId));
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, ¤tThreadId));
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