Skip to content

Commit eecbc18

Browse files
authored
Remove sync call from DetachRootView to fix deadlock, add public QuirkSettings API for backward compatibility (#15113)
1 parent 34d1771 commit eecbc18

5 files changed

Lines changed: 40 additions & 2 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "prerelease",
3+
"comment": "Fix deadlock in ReactInstanceWin::DetachRootView by replacing sync call with async",
4+
"packageName": "react-native-windows",
5+
"email": "copilot@github.com",
6+
"dependentChangeType": "patch"
7+
}

vnext/Microsoft.ReactNative/QuirkSettings.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ winrt::Microsoft::ReactNative::ReactPropertyId<bool> UseRuntimeSchedulerProperty
7777
return propId;
7878
}
7979

80+
winrt::Microsoft::ReactNative::ReactPropertyId<bool> UseRunOnQueueSyncProperty() noexcept {
81+
winrt::Microsoft::ReactNative::ReactPropertyId<bool> propId{L"ReactNative.QuirkSettings", L"UseRunOnQueueSync"};
82+
83+
return propId;
84+
}
85+
8086
#pragma region IDL interface
8187

8288
/*static*/ void QuirkSettings::SetMatchAndroidAndIOSStretchBehavior(
@@ -121,6 +127,12 @@ winrt::Microsoft::ReactNative::ReactPropertyId<bool> UseRuntimeSchedulerProperty
121127
ReactPropertyBag(settings.Properties()).Set(UseRuntimeSchedulerProperty(), value);
122128
}
123129

130+
/*static*/ void QuirkSettings::SetUseRunOnQueueSync(
131+
winrt::Microsoft::ReactNative::ReactInstanceSettings settings,
132+
bool value) noexcept {
133+
ReactPropertyBag(settings.Properties()).Set(UseRunOnQueueSyncProperty(), value);
134+
}
135+
124136
#pragma endregion IDL interface
125137

126138
/*static*/ bool QuirkSettings::GetMatchAndroidAndIOSStretchBehavior(ReactPropertyBag properties) noexcept {
@@ -153,4 +165,8 @@ winrt::Microsoft::ReactNative::ReactPropertyId<bool> UseRuntimeSchedulerProperty
153165
return properties.Get(UseRuntimeSchedulerProperty()).value_or(true);
154166
}
155167

168+
/*static*/ bool QuirkSettings::GetUseRunOnQueueSync(ReactPropertyBag properties) noexcept {
169+
return properties.Get(UseRunOnQueueSyncProperty()).value_or(false);
170+
}
171+
156172
} // namespace winrt::Microsoft::ReactNative::implementation

vnext/Microsoft.ReactNative/QuirkSettings.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ struct QuirkSettings : QuirkSettingsT<QuirkSettings> {
3030
winrt::Microsoft::ReactNative::ReactPropertyBag properties) noexcept;
3131
static bool GetSuppressWindowFocusOnViewFocus(winrt::Microsoft::ReactNative::ReactPropertyBag properties) noexcept;
3232
static bool GetUseRuntimeScheduler(winrt::Microsoft::ReactNative::ReactPropertyBag properties) noexcept;
33+
static bool GetUseRunOnQueueSync(winrt::Microsoft::ReactNative::ReactPropertyBag properties) noexcept;
3334

3435
static bool GetEnableFabric(winrt::Microsoft::ReactNative::ReactPropertyBag properties) noexcept;
3536

@@ -65,6 +66,8 @@ struct QuirkSettings : QuirkSettingsT<QuirkSettings> {
6566
winrt::Microsoft::ReactNative::ReactInstanceSettings settings,
6667
bool value) noexcept;
6768

69+
static void SetUseRunOnQueueSync(winrt::Microsoft::ReactNative::ReactInstanceSettings settings, bool value) noexcept;
70+
6871
#pragma endregion Public API - part of IDL interface
6972
};
7073

vnext/Microsoft.ReactNative/QuirkSettings.idl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ namespace Microsoft.ReactNative
6464
"By default `react-native-windows` will use the new RuntimeScheduler."
6565
"Setting this to false will revert the behavior to previous scheduling logic.")
6666
static void SetUseRuntimeScheduler(ReactInstanceSettings settings, Boolean value);
67+
68+
DOC_STRING(
69+
"By default `react-native-windows` will not call sync JS call: runOnQueueSync."
70+
"Setting this to true will revert the behavior to previous logic and might result in hang.")
71+
static void SetUseRunOnQueueSync(ReactInstanceSettings settings, Boolean value);
6772
}
6873

6974
} // namespace Microsoft.ReactNative

vnext/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,8 +1514,15 @@ void ReactInstanceWin::DetachRootView(facebook::react::IReactRootView *rootView,
15141514
CallJsFunction("AppRegistry", "unmountApplicationComponentAtRootTag", std::move(params));
15151515
}
15161516

1517-
// Give the JS thread time to finish executing
1518-
m_jsMessageThread.Load()->runOnQueueSync([]() {});
1517+
// QUIRK: Legacy sync behavior can be re-enabled via EnableSyncDetachRootView option
1518+
// The sync call was removed to prevent deadlocks with Hermes GC operations
1519+
bool useSyncCall = winrt::Microsoft::ReactNative::implementation::QuirkSettings::GetUseRunOnQueueSync(
1520+
winrt::Microsoft::ReactNative::ReactPropertyBag(m_reactContext->Properties()));
1521+
if (useSyncCall) {
1522+
// Legacy behavior: wait for JS thread to finish executing (can cause deadlocks)
1523+
m_jsMessageThread.Load()->runOnQueueSync([]() {});
1524+
}
1525+
// Default behavior: no synchronization call to prevent deadlocks
15191526
}
15201527

15211528
Mso::CntPtr<IReactInstanceInternal> MakeReactInstance(

0 commit comments

Comments
 (0)