Fix data race with gCurrentGenerationCount

Summary:
Yoga layout can be invoked on multiple threads, and gCurrentGenerationCount is a shared global without synchronization.

Changelog: [General] [Fixed] - Fix an internal thread safety issue in Yoga

Reviewed By: SidharthGuglani

Differential Revision: D18092734

fbshipit-source-id: 85753d139549b4e5507f97a56d589fb6854557fa
This commit is contained in:
Scott Wolchok
2019-10-28 12:38:05 -07:00
committed by Facebook Github Bot
parent 27f42c90db
commit fb07dcff40

View File

@@ -10,6 +10,7 @@
#include <float.h> #include <float.h>
#include <string.h> #include <string.h>
#include <algorithm> #include <algorithm>
#include <atomic>
#include <memory> #include <memory>
#include "Utils.h" #include "Utils.h"
#include "YGNode.h" #include "YGNode.h"
@@ -927,7 +928,7 @@ bool YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(const YGNodeRef node) {
return node->getLayout().doesLegacyStretchFlagAffectsLayout(); return node->getLayout().doesLegacyStretchFlagAffectsLayout();
} }
uint32_t gCurrentGenerationCount = 0; std::atomic<uint32_t> gCurrentGenerationCount(0);
bool YGLayoutNodeInternal( bool YGLayoutNodeInternal(
const YGNodeRef node, const YGNodeRef node,
@@ -1846,7 +1847,7 @@ static float YGNodeComputeFlexBasisForChildren(
const uint32_t generationCount) { const uint32_t generationCount) {
float totalOuterFlexBasis = 0.0f; float totalOuterFlexBasis = 0.0f;
YGNodeRef singleFlexChild = nullptr; YGNodeRef singleFlexChild = nullptr;
const YGVector &children = node->getChildren(); const YGVector& children = node->getChildren();
YGMeasureMode measureModeMainDim = YGMeasureMode measureModeMainDim =
YGFlexDirectionIsRow(mainAxis) ? widthMeasureMode : heightMeasureMode; YGFlexDirectionIsRow(mainAxis) ? widthMeasureMode : heightMeasureMode;
// If there is only one child with flexGrow + flexShrink it means we can set // If there is only one child with flexGrow + flexShrink it means we can set
@@ -4079,7 +4080,7 @@ void YGNodeCalculateLayoutWithContext(
// Increment the generation count. This will force the recursive routine to // Increment the generation count. This will force the recursive routine to
// visit all dirty nodes at least once. Subsequent visits will be skipped if // visit all dirty nodes at least once. Subsequent visits will be skipped if
// the input parameters don't change. // the input parameters don't change.
gCurrentGenerationCount++; gCurrentGenerationCount.fetch_add(1, std::memory_order_relaxed);
node->resolveDimension(); node->resolveDimension();
float width = YGUndefined; float width = YGUndefined;
YGMeasureMode widthMeasureMode = YGMeasureModeUndefined; YGMeasureMode widthMeasureMode = YGMeasureModeUndefined;
@@ -4136,7 +4137,7 @@ void YGNodeCalculateLayoutWithContext(
markerData, markerData,
layoutContext, layoutContext,
0, // tree root 0, // tree root
gCurrentGenerationCount)) { gCurrentGenerationCount.load(std::memory_order_relaxed))) {
node->setPosition( node->setPosition(
node->getLayout().direction(), ownerWidth, ownerHeight, ownerWidth); node->getLayout().direction(), ownerWidth, ownerHeight, ownerWidth);
YGRoundToPixelGrid(node, node->getConfig()->pointScaleFactor, 0.0f, 0.0f); YGRoundToPixelGrid(node, node->getConfig()->pointScaleFactor, 0.0f, 0.0f);
@@ -4167,7 +4168,7 @@ void YGNodeCalculateLayoutWithContext(
nodeWithoutLegacyFlag->resolveDimension(); nodeWithoutLegacyFlag->resolveDimension();
// Recursively mark nodes as dirty // Recursively mark nodes as dirty
nodeWithoutLegacyFlag->markDirtyAndPropogateDownwards(); nodeWithoutLegacyFlag->markDirtyAndPropogateDownwards();
gCurrentGenerationCount++; gCurrentGenerationCount.fetch_add(1, std::memory_order_relaxed);
// Rerun the layout, and calculate the diff // Rerun the layout, and calculate the diff
unsetUseLegacyFlagRecursively(nodeWithoutLegacyFlag); unsetUseLegacyFlagRecursively(nodeWithoutLegacyFlag);
LayoutData layoutMarkerData = {}; LayoutData layoutMarkerData = {};
@@ -4186,7 +4187,7 @@ void YGNodeCalculateLayoutWithContext(
layoutMarkerData, layoutMarkerData,
layoutContext, layoutContext,
0, // tree root 0, // tree root
gCurrentGenerationCount)) { gCurrentGenerationCount.load(std::memory_order_relaxed))) {
nodeWithoutLegacyFlag->setPosition( nodeWithoutLegacyFlag->setPosition(
nodeWithoutLegacyFlag->getLayout().direction(), nodeWithoutLegacyFlag->getLayout().direction(),
ownerWidth, ownerWidth,