Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow recursive calls to schedulerShouldRenderTransactions without deadlocks #44725

Closed
wants to merge 2 commits into from

Conversation

rubennorte
Copy link
Contributor

Summary:
Changelog: [internal]

Context

We're currently testing synchronous state updates in Fabric (committing shadow trees for state updates synchronously in the thread where they were dispatched, instead of always scheduling it in the JS thread).

In these experiments we saw a problem caused by a recent change in the Android mounting layer (done to fix a problem with the Event Loop) where we were doing the mount operations inside a mutex lock. The problem is that we didn't have recursive commit+mount operations (because we were dispatching state updates in the JS thread) but now that we do we get a deadlock here.

{F1659804385}

These recursive commit+mount operations happen because it's possible to trigger state updates while we mount changes in the host platform (e.g.: we create the scroll view and we update the state to set the content offset). Those state updates trigger more mount operations, which deadlock in the mentioned place.

Changes

This fixes the described issue by restricting the lock only to access the list of pending operations, but not to apply them. In the current implementation, mountingManager->executeMount is protected by the lock, whereas in the new version it isn't (so it can be safely called recursively). The synchronization of the mount operations is done directly at the mounting layer on Android.

Differential Revision: D57968936

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label May 30, 2024
@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D57968936

rubennorte added a commit to rubennorte/react-native that referenced this pull request May 30, 2024
…adlocks (facebook#44725)

Summary:

Changelog: [internal]

## Context

We're currently testing synchronous state updates in Fabric (committing shadow trees for state updates synchronously in the thread where they were dispatched, instead of always scheduling it in the JS thread).

In these experiments we saw a problem caused by a recent change in the Android mounting layer (done to fix a problem with the Event Loop) where we were doing the mount operations inside a mutex lock. The problem is that we didn't have recursive commit+mount operations (because we were dispatching state updates in the JS thread) but now that we do we get a deadlock here.

 {F1659804385} 

These recursive commit+mount operations happen because it's possible to trigger state updates while we mount changes in the host platform (e.g.: we create the scroll view and we update the state to set the content offset). Those state updates trigger more mount operations, which deadlock in the mentioned place.

## Changes

This fixes the described issue by restricting the lock only to access the list of pending operations, but not to apply them. In the current implementation, `mountingManager->executeMount` is protected by the lock, whereas in the new version it isn't (so it can be safely called recursively). The synchronization of the mount operations is done directly at the mounting layer on Android.

Differential Revision: D57968936
@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D57968936

rubennorte added a commit to rubennorte/react-native that referenced this pull request May 30, 2024
…adlocks (facebook#44725)

Summary:

Changelog: [internal]

## Context

We're currently testing synchronous state updates in Fabric (committing shadow trees for state updates synchronously in the thread where they were dispatched, instead of always scheduling it in the JS thread).

In these experiments we saw a problem caused by a recent change in the Android mounting layer (done to fix a problem with the Event Loop) where we were doing the mount operations inside a mutex lock. The problem is that we didn't have recursive commit+mount operations (because we were dispatching state updates in the JS thread) but now that we do we get a deadlock here.

 {F1659804385} 

These recursive commit+mount operations happen because it's possible to trigger state updates while we mount changes in the host platform (e.g.: we create the scroll view and we update the state to set the content offset). Those state updates trigger more mount operations, which deadlock in the mentioned place.

## Changes

This fixes the described issue by restricting the lock only to access the list of pending operations, but not to apply them. In the current implementation, `mountingManager->executeMount` is protected by the lock, whereas in the new version it isn't (so it can be safely called recursively). The synchronization of the mount operations is done directly at the mounting layer on Android.

Differential Revision: D57968936
rubennorte added a commit to rubennorte/react-native that referenced this pull request May 30, 2024
…without deadlocks (facebook#44725)

Summary:

Changelog: [internal]

## Context

We're currently testing synchronous state updates in Fabric (committing shadow trees for state updates synchronously in the thread where they were dispatched, instead of always scheduling it in the JS thread).

In these experiments we saw a problem caused by a recent change in the Android mounting layer (done to fix a problem with the Event Loop) where we were doing the mount operations inside a mutex lock. The problem is that we didn't have recursive commit+mount operations (because we were dispatching state updates in the JS thread) but now that we do we get a deadlock here.

 {F1659804385} 

These recursive commit+mount operations happen because it's possible to trigger state updates while we mount changes in the host platform (e.g.: we create the scroll view and we update the state to set the content offset). Those state updates trigger more mount operations, which deadlock in the mentioned place.

## Changes

This fixes the described issue by restricting the lock only to access the list of pending operations, but not to apply them. In the current implementation, `mountingManager->executeMount` is protected by the lock, whereas in the new version it isn't (so it can be safely called recursively). The synchronization of the mount operations is done directly at the mounting layer on Android.

Differential Revision: D57968936
…ached (facebook#44724)

Summary:

Changelog: [internal]

Batching operations at this layer was wrong because these are the operations that were already flushed by the mounting layer but were accumulated in `SurfaceMountingManager` because the root view wasn't created.

These operations should be executed before anything else that's scheduled in the `MountItemDispatcher`, so we should never batch them. The problem this was trying to solve is solved in a different way in D57968937.

This was gated so this shouldn't affect any current usages.

Reviewed By: sammy-SC

Differential Revision: D57968939
…adlocks (facebook#44725)

Summary:

Changelog: [internal]

## Context

We're currently testing synchronous state updates in Fabric (committing shadow trees for state updates synchronously in the thread where they were dispatched, instead of always scheduling it in the JS thread).

In these experiments we saw a problem caused by a recent change in the Android mounting layer (done to fix a problem with the Event Loop) where we were doing the mount operations inside a mutex lock. The problem is that we didn't have recursive commit+mount operations (because we were dispatching state updates in the JS thread) but now that we do we get a deadlock here.

 {F1659804385} 

These recursive commit+mount operations happen because it's possible to trigger state updates while we mount changes in the host platform (e.g.: we create the scroll view and we update the state to set the content offset). Those state updates trigger more mount operations, which deadlock in the mentioned place.

## Changes

This fixes the described issue by restricting the lock only to access the list of pending operations, but not to apply them. In the current implementation, `mountingManager->executeMount` is protected by the lock, whereas in the new version it isn't (so it can be safely called recursively). The synchronization of the mount operations is done directly at the mounting layer on Android.

Reviewed By: sammy-SC

Differential Revision: D57968936
@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D57968936

@analysis-bot
Copy link

Platform Engine Arch Size (bytes) Diff
android hermes arm64-v8a 19,543,412 +16,394
android hermes armeabi-v7a n/a --
android hermes x86 n/a --
android hermes x86_64 n/a --
android jsc arm64-v8a 22,912,953 +16,420
android jsc armeabi-v7a n/a --
android jsc x86 n/a --
android jsc x86_64 n/a --

Base commit: 32b5c96
Branch: main

@facebook-github-bot facebook-github-bot added the Merged This PR has been merged. label May 30, 2024
@facebook-github-bot
Copy link
Contributor

This pull request has been merged in d1c7201.

kosmydel pushed a commit to kosmydel/react-native that referenced this pull request Jun 11, 2024
…adlocks (facebook#44725)

Summary:
Pull Request resolved: facebook#44725

Changelog: [internal]

## Context

We're currently testing synchronous state updates in Fabric (committing shadow trees for state updates synchronously in the thread where they were dispatched, instead of always scheduling it in the JS thread).

In these experiments we saw a problem caused by a recent change in the Android mounting layer (done to fix a problem with the Event Loop) where we were doing the mount operations inside a mutex lock. The problem is that we didn't have recursive commit+mount operations (because we were dispatching state updates in the JS thread) but now that we do we get a deadlock here.

 {F1659804385}

These recursive commit+mount operations happen because it's possible to trigger state updates while we mount changes in the host platform (e.g.: we create the scroll view and we update the state to set the content offset). Those state updates trigger more mount operations, which deadlock in the mentioned place.

## Changes

This fixes the described issue by restricting the lock only to access the list of pending operations, but not to apply them. In the current implementation, `mountingManager->executeMount` is protected by the lock, whereas in the new version it isn't (so it can be safely called recursively). The synchronization of the mount operations is done directly at the mounting layer on Android.

Reviewed By: sammy-SC

Differential Revision: D57968936

fbshipit-source-id: 52f996d212cad691646610632b03b5223e7e90ca
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. fb-exported Merged This PR has been merged. p: Facebook Partner: Facebook Partner
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants