Fabric: Fixed possible race condition in ShadowTree::complete

Summary: Quite obviously, having a `complete` method which accepts only `newRootShadowNode` was a baaad idea. When we `complete` or `commit` we always have to have two nodes (before and after). And only after layout and right before swapping (and acquiring the mutex) we have to verify that *current* root node is still the same as it was when we initialized the transaction (if not, we have to abort).

Reviewed By: mdvacca

Differential Revision: D10201902

fbshipit-source-id: 15adc78c5d31d6fd39fd7fc6e53203a5539717a8
This commit is contained in:
Valentin Shergin 2018-10-09 16:25:10 -07:00 committed by Facebook Github Bot
parent 4ce57cb7c7
commit 01af828d16
2 changed files with 27 additions and 14 deletions

View File

@ -62,27 +62,31 @@ void ShadowTree::synchronize(std::function<void(void)> function) const {
#pragma mark - Layout
Size ShadowTree::measure(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const {
auto newRootShadowNode = cloneRootShadowNode(layoutConstraints, layoutContext);
auto newRootShadowNode = cloneRootShadowNode(getRootShadowNode(), layoutConstraints, layoutContext);
newRootShadowNode->layout();
return newRootShadowNode->getLayoutMetrics().frame.size;
}
bool ShadowTree::constraintLayout(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const {
auto newRootShadowNode = cloneRootShadowNode(layoutConstraints, layoutContext);
return complete(newRootShadowNode);
auto oldRootShadowNode = getRootShadowNode();
auto newRootShadowNode = cloneRootShadowNode(oldRootShadowNode, layoutConstraints, layoutContext);
return complete(oldRootShadowNode, newRootShadowNode);
}
#pragma mark - Commiting
UnsharedRootShadowNode ShadowTree::cloneRootShadowNode(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const {
auto oldRootShadowNode = getRootShadowNode();
const auto &props = std::make_shared<const RootProps>(*oldRootShadowNode->getProps(), layoutConstraints, layoutContext);
UnsharedRootShadowNode ShadowTree::cloneRootShadowNode(
const SharedRootShadowNode &oldRootShadowNode,
const LayoutConstraints &layoutConstraints,
const LayoutContext &layoutContext
) const {
auto props = std::make_shared<const RootProps>(*oldRootShadowNode->getProps(), layoutConstraints, layoutContext);
auto newRootShadowNode =
std::make_shared<RootShadowNode>(*oldRootShadowNode, ShadowNodeFragment {.props = props});
return newRootShadowNode;
}
bool ShadowTree::complete(const SharedShadowNodeUnsharedList &rootChildNodes) const {
bool ShadowTree::complete(const SharedShadowNodeUnsharedList &rootChildNodes) const {
auto oldRootShadowNode = getRootShadowNode();
auto newRootShadowNode =
std::make_shared<RootShadowNode>(
@ -92,14 +96,14 @@ bool ShadowTree::complete(const SharedShadowNodeUnsharedList &rootChildNodes) c
}
);
return complete(newRootShadowNode);
return complete(oldRootShadowNode, newRootShadowNode);
}
bool ShadowTree::complete(UnsharedRootShadowNode newRootShadowNode) const {
SharedRootShadowNode oldRootShadowNode = getRootShadowNode();
bool ShadowTree::complete(
const SharedRootShadowNode &oldRootShadowNode,
const UnsharedRootShadowNode &newRootShadowNode
) const {
newRootShadowNode->layout();
newRootShadowNode->sealRecursive();
auto mutations = calculateShadowViewMutations(

View File

@ -87,14 +87,23 @@ public:
ShadowTreeDelegate const *getDelegate() const;
private:
UnsharedRootShadowNode cloneRootShadowNode(
const SharedRootShadowNode &oldRootShadowNode,
const LayoutConstraints &layoutConstraints,
const LayoutContext &layoutContext
) const;
bool complete(
const SharedRootShadowNode &oldRootShadowNode,
const UnsharedRootShadowNode &newRootShadowNode
) const;
UnsharedRootShadowNode cloneRootShadowNode(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const;
bool complete(UnsharedRootShadowNode newRootShadowNode) const;
bool commit(
const SharedRootShadowNode &oldRootShadowNode,
const SharedRootShadowNode &newRootShadowNode,
const ShadowViewMutationList &mutations
) const;
void toggleEventEmitters(const ShadowViewMutationList &mutations) const;
void emitLayoutEvents(const ShadowViewMutationList &mutations) const;