mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-01 17:23:59 +00:00
Bug 1457590 - Add the HitTestingTreeNodeAutoLock class. r=botond
This adds the HitTestingTreeNodeAutoLock RAII class that allows using a HitTestingTreeNode safely outside a tree lock, and ensures that the node won't get destroyed or recycled concurrently. MozReview-Commit-ID: 8Tb3vdIeUgr --HG-- extra : rebase_source : 6eed3e733edcaa4088da52882a9b3dc8c2355c2e
This commit is contained in:
parent
46df7cfee3
commit
6acdee2bb0
@ -24,6 +24,7 @@ HitTestingTreeNode::HitTestingTreeNode(AsyncPanZoomController* aApzc,
|
||||
LayersId aLayersId)
|
||||
: mApzc(aApzc)
|
||||
, mIsPrimaryApzcHolder(aIsPrimaryHolder)
|
||||
, mLocked(false)
|
||||
, mLayersId(aLayersId)
|
||||
, mScrollbarAnimationId(0)
|
||||
, mFixedPosTarget(FrameMetrics::NULL_SCROLL_ID)
|
||||
@ -73,7 +74,7 @@ HitTestingTreeNode::Destroy()
|
||||
bool
|
||||
HitTestingTreeNode::IsRecyclable(const RecursiveMutexAutoLock& aProofOfTreeLock)
|
||||
{
|
||||
return !IsPrimaryHolder();
|
||||
return !(IsPrimaryHolder() || mLocked);
|
||||
}
|
||||
|
||||
void
|
||||
@ -406,5 +407,58 @@ HitTestingTreeNode::SetApzcParent(AsyncPanZoomController* aParent)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HitTestingTreeNode::Lock(const RecursiveMutexAutoLock& aProofOfTreeLock)
|
||||
{
|
||||
MOZ_ASSERT(!mLocked);
|
||||
mLocked = true;
|
||||
}
|
||||
|
||||
void
|
||||
HitTestingTreeNode::Unlock(const RecursiveMutexAutoLock& aProofOfTreeLock)
|
||||
{
|
||||
MOZ_ASSERT(mLocked);
|
||||
mLocked = false;
|
||||
}
|
||||
|
||||
HitTestingTreeNodeAutoLock::HitTestingTreeNodeAutoLock()
|
||||
: mTreeMutex(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
HitTestingTreeNodeAutoLock::~HitTestingTreeNodeAutoLock()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void
|
||||
HitTestingTreeNodeAutoLock::Initialize(const RecursiveMutexAutoLock& aProofOfTreeLock,
|
||||
already_AddRefed<HitTestingTreeNode> aNode,
|
||||
RecursiveMutex& aTreeMutex)
|
||||
{
|
||||
MOZ_ASSERT(!mNode);
|
||||
|
||||
mNode = aNode;
|
||||
mTreeMutex = &aTreeMutex;
|
||||
|
||||
mNode->Lock(aProofOfTreeLock);
|
||||
}
|
||||
|
||||
void
|
||||
HitTestingTreeNodeAutoLock::Clear()
|
||||
{
|
||||
if (!mNode) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(mTreeMutex);
|
||||
|
||||
{ // scope lock
|
||||
RecursiveMutexAutoLock lock(*mTreeMutex);
|
||||
mNode->Unlock(lock);
|
||||
}
|
||||
mNode = nullptr;
|
||||
mTreeMutex = nullptr;
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
@ -48,6 +48,13 @@ class AsyncPanZoomController;
|
||||
* Accessing the compositor layer tree can only be done on the compositor
|
||||
* thread, and so it is simpler to make a copy of the hit-testing related
|
||||
* properties into a separate tree.
|
||||
*
|
||||
* The tree pointers on the node (mLastChild, etc.) can only be manipulated
|
||||
* while holding the APZ tree lock. Any code that wishes to use a
|
||||
* HitTestingTreeNode outside of holding the tree lock should do so by using
|
||||
* the HitTestingTreeNodeAutoLock wrapper, which prevents the node from
|
||||
* being recycled (and also holds a RefPtr to the node to prevent it from
|
||||
* getting freed).
|
||||
*/
|
||||
class HitTestingTreeNode {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(HitTestingTreeNode);
|
||||
@ -137,6 +144,12 @@ public:
|
||||
void Dump(const char* aPrefix = "") const;
|
||||
|
||||
private:
|
||||
friend class HitTestingTreeNodeAutoLock;
|
||||
// Functions that are private but called from HitTestingTreeNodeAutoLock
|
||||
void Lock(const RecursiveMutexAutoLock& aProofOfTreeLock);
|
||||
void Unlock(const RecursiveMutexAutoLock& aProofOfTreeLock);
|
||||
|
||||
|
||||
void SetApzcParent(AsyncPanZoomController* aApzc);
|
||||
|
||||
RefPtr<HitTestingTreeNode> mLastChild;
|
||||
@ -145,6 +158,7 @@ private:
|
||||
|
||||
RefPtr<AsyncPanZoomController> mApzc;
|
||||
bool mIsPrimaryApzcHolder;
|
||||
bool mLocked;
|
||||
|
||||
LayersId mLayersId;
|
||||
|
||||
@ -193,6 +207,33 @@ private:
|
||||
EventRegionsOverride mOverride;
|
||||
};
|
||||
|
||||
/**
|
||||
* A class that allows safe usage of a HitTestingTreeNode outside of the APZ
|
||||
* tree lock. In general, this class should be Initialize()'d inside the tree
|
||||
* lock (enforced by the proof-of-lock to Initialize), and then can be returned
|
||||
* to a scope outside the tree lock and used safely. Upon destruction or
|
||||
* Clear() being called, it unlocks the underlying node at which point it can
|
||||
* be recycled or freed.
|
||||
*/
|
||||
class MOZ_RAII HitTestingTreeNodeAutoLock
|
||||
{
|
||||
public:
|
||||
HitTestingTreeNodeAutoLock();
|
||||
HitTestingTreeNodeAutoLock(const HitTestingTreeNodeAutoLock&) = delete;
|
||||
HitTestingTreeNodeAutoLock& operator=(const HitTestingTreeNodeAutoLock&) = delete;
|
||||
HitTestingTreeNodeAutoLock(HitTestingTreeNodeAutoLock&&) = delete;
|
||||
~HitTestingTreeNodeAutoLock();
|
||||
|
||||
void Initialize(const RecursiveMutexAutoLock& aProofOfTreeLock,
|
||||
already_AddRefed<HitTestingTreeNode> aNode,
|
||||
RecursiveMutex& aTreeMutex);
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
RefPtr<HitTestingTreeNode> mNode;
|
||||
RecursiveMutex* mTreeMutex;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user