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:
parent
e90f5fa263
commit
4876928f9e
|
@ -38,6 +38,11 @@ Tag ShadowTree::getRootTag() const {
|
||||||
return rootTag_;
|
return rootTag_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SharedRootShadowNode ShadowTree::getRootShadowNode() const {
|
||||||
|
std::lock_guard<std::mutex> lock(commitMutex_);
|
||||||
|
return rootShadowNode_;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Layout
|
#pragma mark - Layout
|
||||||
|
|
||||||
Size ShadowTree::measure(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const {
|
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;
|
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);
|
auto newRootShadowNode = cloneRootShadowNode(layoutConstraints, layoutContext);
|
||||||
complete(newRootShadowNode);
|
complete(newRootShadowNode);
|
||||||
}
|
}
|
||||||
|
@ -54,15 +59,15 @@ void ShadowTree::constraintLayout(const LayoutConstraints &layoutConstraints, co
|
||||||
#pragma mark - Commiting
|
#pragma mark - Commiting
|
||||||
|
|
||||||
UnsharedRootShadowNode ShadowTree::cloneRootShadowNode(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const {
|
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);
|
const auto &props = std::make_shared<const RootProps>(*oldRootShadowNode->getProps(), layoutConstraints, layoutContext);
|
||||||
auto newRootShadowNode =
|
auto newRootShadowNode =
|
||||||
std::make_shared<RootShadowNode>(*oldRootShadowNode, ShadowNodeFragment {.props = props});
|
std::make_shared<RootShadowNode>(*oldRootShadowNode, ShadowNodeFragment {.props = props});
|
||||||
return newRootShadowNode;
|
return newRootShadowNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShadowTree::complete(const SharedShadowNodeUnsharedList &rootChildNodes) {
|
void ShadowTree::complete(const SharedShadowNodeUnsharedList &rootChildNodes) const {
|
||||||
auto oldRootShadowNode = rootShadowNode_;
|
auto oldRootShadowNode = getRootShadowNode();
|
||||||
auto newRootShadowNode =
|
auto newRootShadowNode =
|
||||||
std::make_shared<RootShadowNode>(
|
std::make_shared<RootShadowNode>(
|
||||||
*oldRootShadowNode,
|
*oldRootShadowNode,
|
||||||
|
@ -74,8 +79,8 @@ void ShadowTree::complete(const SharedShadowNodeUnsharedList &rootChildNodes) {
|
||||||
complete(newRootShadowNode);
|
complete(newRootShadowNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShadowTree::complete(UnsharedRootShadowNode newRootShadowNode) {
|
void ShadowTree::complete(UnsharedRootShadowNode newRootShadowNode) const {
|
||||||
SharedRootShadowNode oldRootShadowNode = rootShadowNode_;
|
SharedRootShadowNode oldRootShadowNode = getRootShadowNode();
|
||||||
|
|
||||||
newRootShadowNode->layout();
|
newRootShadowNode->layout();
|
||||||
|
|
||||||
|
@ -99,7 +104,7 @@ bool ShadowTree::commit(
|
||||||
const SharedRootShadowNode &oldRootShadowNode,
|
const SharedRootShadowNode &oldRootShadowNode,
|
||||||
const SharedRootShadowNode &newRootShadowNode,
|
const SharedRootShadowNode &newRootShadowNode,
|
||||||
const ShadowViewMutationList &mutations
|
const ShadowViewMutationList &mutations
|
||||||
) {
|
) const {
|
||||||
std::lock_guard<std::mutex> lock(commitMutex_);
|
std::lock_guard<std::mutex> lock(commitMutex_);
|
||||||
|
|
||||||
if (oldRootShadowNode != rootShadowNode_) {
|
if (oldRootShadowNode != rootShadowNode_) {
|
||||||
|
@ -109,10 +114,11 @@ bool ShadowTree::commit(
|
||||||
rootShadowNode_ = newRootShadowNode;
|
rootShadowNode_ = newRootShadowNode;
|
||||||
|
|
||||||
toggleEventEmitters(mutations);
|
toggleEventEmitters(mutations);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShadowTree::emitLayoutEvents(const ShadowViewMutationList &mutations) {
|
void ShadowTree::emitLayoutEvents(const ShadowViewMutationList &mutations) const {
|
||||||
for (const auto &mutation : mutations) {
|
for (const auto &mutation : mutations) {
|
||||||
// Only `Insert` and `Update` mutations can affect layout metrics.
|
// Only `Insert` and `Update` mutations can affect layout metrics.
|
||||||
if (
|
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());
|
std::lock_guard<std::recursive_mutex> lock(EventEmitter::DispatchMutex());
|
||||||
|
|
||||||
for (const auto &mutation : mutations) {
|
for (const auto &mutation : mutations) {
|
||||||
|
|
|
@ -49,17 +49,19 @@ public:
|
||||||
/*
|
/*
|
||||||
* Applies given `layoutConstraints` and `layoutContext` and commit
|
* Applies given `layoutConstraints` and `layoutContext` and commit
|
||||||
* the new shadow tree.
|
* the new shadow tree.
|
||||||
|
* Returns `true` if the operation is finished successfully.
|
||||||
* Can be called from any thread.
|
* 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
|
#pragma mark - Application
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a new shadow tree with given `rootChildNodes` and commit.
|
* Create a new shadow tree with given `rootChildNodes` and commit.
|
||||||
* Can be called from any thread.
|
* 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
|
#pragma mark - Delegate
|
||||||
|
|
||||||
|
@ -74,17 +76,22 @@ public:
|
||||||
private:
|
private:
|
||||||
|
|
||||||
UnsharedRootShadowNode cloneRootShadowNode(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const;
|
UnsharedRootShadowNode cloneRootShadowNode(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const;
|
||||||
void complete(UnsharedRootShadowNode newRootShadowNode);
|
void complete(UnsharedRootShadowNode newRootShadowNode) const;
|
||||||
bool commit(
|
bool commit(
|
||||||
const SharedRootShadowNode &oldRootShadowNode,
|
const SharedRootShadowNode &oldRootShadowNode,
|
||||||
const SharedRootShadowNode &newRootShadowNode,
|
const SharedRootShadowNode &newRootShadowNode,
|
||||||
const ShadowViewMutationList &mutations
|
const ShadowViewMutationList &mutations
|
||||||
);
|
) const;
|
||||||
void toggleEventEmitters(const ShadowViewMutationList &mutations);
|
void toggleEventEmitters(const ShadowViewMutationList &mutations) const;
|
||||||
void emitLayoutEvents(const ShadowViewMutationList &mutations);
|
void emitLayoutEvents(const ShadowViewMutationList &mutations) const;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return `rootShadowNodeMutex_` protected by `commitMutex_`.
|
||||||
|
*/
|
||||||
|
SharedRootShadowNode getRootShadowNode() const;
|
||||||
|
|
||||||
const Tag rootTag_;
|
const Tag rootTag_;
|
||||||
SharedRootShadowNode rootShadowNode_;
|
mutable SharedRootShadowNode rootShadowNode_; // Protected by `commitMutex_`.
|
||||||
ShadowTreeDelegate const *delegate_;
|
ShadowTreeDelegate const *delegate_;
|
||||||
mutable std::mutex commitMutex_;
|
mutable std::mutex commitMutex_;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue