You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
RuntimeExecutor: Fix sync js execution from main thread
Summary:
# Problem
Sync rendering/events (i.e: execute js now below), when used in conjunction with js -> ui sync calls, can deadlock react native:
## Deadlock #1
**Main thread**: execute js now:
* Main thread puts a block on the js queue, to capture the runtime.
* Main thread then then goes to sleep, waiting for runtime to be captured
**JS thread**: execute ui code synchronously:
* Js thread schedules a block on the ui thread
* Js thread then goes to sleep, waiting for that block to execute.
* **The application deadlocks**
| {F1978009555} | {F1978009612} |
## Deadlock #2
**JS thread**: execute ui code synchronously:
* Js thread schedules a block on the ui thread
* Js thread then goes to sleep waiting for that block to execute.
**Main thread**: execute js now:
* Main thread puts a block on the js queue, to capture the runtime.
* Main thread then then goes to sleep, waiting for runtime to be captured
* **The application deadlocks.**
| {F1978009690} | {F1978009701} |
# Changes
This diff attempts to fix those deadlocks. How:
* This diff introduces a stateful "execute js now" coordinator.
* In "execute ui code synchronously" (js thread):
* Before going to sleep, the js thread posts its ui work to the "execute js now" coordinator.
* In "execute js now" (main thread):
* Before trying to capture the runtime, the main thread executes "pending ui work", if it exists.
* While the main thread is sleeping, waiting for runtime capture, it can be woken up, and asked to execute "pending ui work."
## Mitigation: Deadlock #1
**Main thread**: execute js now:
* Main thread puts a block on the js queue, to capture the runtime.
* Main thread then then goes to sleep, waiting for runtime to be captured
**JS Thread**: execute ui code synchronously:
* Js thread schedules this block on the ui thread.
* ***New***: Js thread also assigns this block to the coordinator. *And wakes up the main thread*.
* Js thread goes to sleep.
The main thread wakes up:
* Main thread **executes** the ui block assigned to the coordinator. **This cancels the ui block scheduled on the main queue.**
* Main thread goes back to sleep.
* The js thread wakes up, moves on to the next task.
The runtime is captured by the main thread.
| {F1978010383} | {F1978010363} | {F1978010371} | {F1978010379}
## Mitigation: Deadlock #2
**JS Thread**: execute ui code synchronously:
* Js thread schedules this block on the ui thread.
* ***New***: Js thread also assigns this block to the coordinator. *And wakes up the main thread*.
* Js thread goes to sleep.
**Main thread**: execute js now
* Main thread executes the ui block immediately. (This cancels the ui block on the main queue).
* Js thread wakes up and moves onto the next task.
Main thread captures the runtime.
| {F1978010525} | {F1978010533} | {F1978010542} |
Differential Revision: D74769326
Copy file name to clipboardExpand all lines: packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.h
Copy file name to clipboardExpand all lines: packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.mm
@"Lazily setting up TurboModule \"%s\" on the main queue. This could deadlock react native, if it happens during sync rendering. Please fix this by avoiding lazy main queue setup.",
0 commit comments