Fabric: Improved thread-safety in ShadowTree

Summary: With new `ShadowTree::getRootShadowNode()` method all access to rootShadowNode_ is protected by commit mutex.

Reviewed By: mdvacca

Differential Revision: D10159456

fbshipit-source-id: 0bc8676ca2564a8ef95d60e912356e99d9f172c1
This commit is contained in:
Valentin Shergin 2018-10-09 16:24:57 -07:00 committed by Facebook Github Bot
parent e90f5fa263
commit 4876928f9e
2 changed files with 29 additions and 16 deletions

View File

@ -38,6 +38,11 @@ Tag ShadowTree::getRootTag() const {
return rootTag_;
}
SharedRootShadowNode ShadowTree::getRootShadowNode() const {
std::lock_guard<std::mutex> lock(commitMutex_);
return rootShadowNode_;
}
#pragma mark - Layout
Size ShadowTree::measure(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const {
@ -46,7 +51,7 @@ Size ShadowTree::measure(const LayoutConstraints &layoutConstraints, const Layou
return newRootShadowNode->getLayoutMetrics().frame.size;
}
void ShadowTree::constraintLayout(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) {
void ShadowTree::constraintLayout(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const {
auto newRootShadowNode = cloneRootShadowNode(layoutConstraints, layoutContext);
complete(newRootShadowNode);
}
@ -54,15 +59,15 @@ void ShadowTree::constraintLayout(const LayoutConstraints &layoutConstraints, co
#pragma mark - Commiting
UnsharedRootShadowNode ShadowTree::cloneRootShadowNode(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const {
auto oldRootShadowNode = rootShadowNode_;
auto oldRootShadowNode = getRootShadowNode();
const auto &props = std::make_shared<const RootProps>(*oldRootShadowNode->getProps(), layoutConstraints, layoutContext);
auto newRootShadowNode =
std::make_shared<RootShadowNode>(*oldRootShadowNode, ShadowNodeFragment {.props = props});
return newRootShadowNode;
}
void ShadowTree::complete(const SharedShadowNodeUnsharedList &rootChildNodes) {
auto oldRootShadowNode = rootShadowNode_;
void ShadowTree::complete(const SharedShadowNodeUnsharedList &rootChildNodes) const {
auto oldRootShadowNode = getRootShadowNode();
auto newRootShadowNode =
std::make_shared<RootShadowNode>(
*oldRootShadowNode,
@ -74,8 +79,8 @@ void ShadowTree::complete(const SharedShadowNodeUnsharedList &rootChildNodes) {
complete(newRootShadowNode);
}
void ShadowTree::complete(UnsharedRootShadowNode newRootShadowNode) {
SharedRootShadowNode oldRootShadowNode = rootShadowNode_;
void ShadowTree::complete(UnsharedRootShadowNode newRootShadowNode) const {
SharedRootShadowNode oldRootShadowNode = getRootShadowNode();
newRootShadowNode->layout();
@ -99,7 +104,7 @@ bool ShadowTree::commit(
const SharedRootShadowNode &oldRootShadowNode,
const SharedRootShadowNode &newRootShadowNode,
const ShadowViewMutationList &mutations
) {
) const {
std::lock_guard<std::mutex> lock(commitMutex_);
if (oldRootShadowNode != rootShadowNode_) {
@ -109,10 +114,11 @@ bool ShadowTree::commit(
rootShadowNode_ = newRootShadowNode;
toggleEventEmitters(mutations);
return true;
}
void ShadowTree::emitLayoutEvents(const ShadowViewMutationList &mutations) {
void ShadowTree::emitLayoutEvents(const ShadowViewMutationList &mutations) const {
for (const auto &mutation : mutations) {
// Only `Insert` and `Update` mutations can affect layout metrics.
if (
@ -147,7 +153,7 @@ void ShadowTree::emitLayoutEvents(const ShadowViewMutationList &mutations) {
}
}
void ShadowTree::toggleEventEmitters(const ShadowViewMutationList &mutations) {
void ShadowTree::toggleEventEmitters(const ShadowViewMutationList &mutations) const {
std::lock_guard<std::recursive_mutex> lock(EventEmitter::DispatchMutex());
for (const auto &mutation : mutations) {

View File

@ -49,17 +49,19 @@ public:
/*
* Applies given `layoutConstraints` and `layoutContext` and commit
* the new shadow tree.
* Returns `true` if the operation is finished successfully.
* Can be called from any thread.
*/
void constraintLayout(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext);
void constraintLayout(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const;
#pragma mark - Application
/*
* Create a new shadow tree with given `rootChildNodes` and commit.
* Can be called from any thread.
* Returns `true` if the operation is finished successfully.
*/
void complete(const SharedShadowNodeUnsharedList &rootChildNodes);
void complete(const SharedShadowNodeUnsharedList &rootChildNodes) const;
#pragma mark - Delegate
@ -74,17 +76,22 @@ public:
private:
UnsharedRootShadowNode cloneRootShadowNode(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const;
void complete(UnsharedRootShadowNode newRootShadowNode);
void complete(UnsharedRootShadowNode newRootShadowNode) const;
bool commit(
const SharedRootShadowNode &oldRootShadowNode,
const SharedRootShadowNode &newRootShadowNode,
const ShadowViewMutationList &mutations
);
void toggleEventEmitters(const ShadowViewMutationList &mutations);
void emitLayoutEvents(const ShadowViewMutationList &mutations);
) const;
void toggleEventEmitters(const ShadowViewMutationList &mutations) const;
void emitLayoutEvents(const ShadowViewMutationList &mutations) const;
/*
* Return `rootShadowNodeMutex_` protected by `commitMutex_`.
*/
SharedRootShadowNode getRootShadowNode() const;
const Tag rootTag_;
SharedRootShadowNode rootShadowNode_;
mutable SharedRootShadowNode rootShadowNode_; // Protected by `commitMutex_`.
ShadowTreeDelegate const *delegate_;
mutable std::mutex commitMutex_;
};