mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
RuntimeExecutor: Create an ios fork of sync ui thread utils
Summary: RuntimeExecutor.h has sync ui thread utils: * executeSynchronouslyOnSameThread_CAN_DEADLOCK The ios platform has js -> ui sync calls. This util, when it executes concurrently with those sync calls, deadlocks react native. On ios, we're going to resolve these deadlocks, which'll involve customizing this util: D74769326. Therefore, this diff forks an implementation of these sync ui thread utils for ios. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D74901907 fbshipit-source-id: f502df4216e9ba57f458435c696a2f086becf24f
This commit is contained in:
committed by
Facebook GitHub Bot
parent
8f2e981ab7
commit
b8ce7b837f
@@ -68,6 +68,7 @@ Pod::Spec.new do |s|
|
||||
s.dependency "React-defaultsnativemodule"
|
||||
s.dependency 'React-hermes'
|
||||
|
||||
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
|
||||
add_dependency(s, "ReactCommon", :subspec => "turbomodule/core", :additional_framework_paths => ["react/nativemodule/core"])
|
||||
add_dependency(s, "React-NativeModulesApple")
|
||||
add_dependency(s, "React-runtimescheduler")
|
||||
|
||||
@@ -126,6 +126,7 @@ Pod::Spec.new do |s|
|
||||
|
||||
s.resource_bundles = {'React-Core_privacy' => 'React/Resources/PrivacyInfo.xcprivacy'}
|
||||
|
||||
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
|
||||
add_dependency(s, "React-jsinspector", :framework_name => 'jsinspector_modern')
|
||||
add_dependency(s, "React-jsinspectorcdp", :framework_name => 'jsinspector_moderncdp')
|
||||
add_dependency(s, "React-jsitooling", :framework_name => "JSITooling")
|
||||
|
||||
@@ -52,6 +52,8 @@ Pod::Spec.new do |s|
|
||||
s.dependency "React-RCTImage", version
|
||||
s.dependency "React-jsi", version
|
||||
s.dependency 'React-RCTBlob'
|
||||
|
||||
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
|
||||
add_dependency(s, "React-jsinspector", :framework_name => 'jsinspector_modern')
|
||||
add_dependency(s, "React-jsinspectorcdp", :framework_name => 'jsinspector_moderncdp')
|
||||
add_dependency(s, "React-jsinspectortracing", :framework_name => 'jsinspector_moderntracing')
|
||||
|
||||
@@ -85,6 +85,7 @@ Pod::Spec.new do |s|
|
||||
add_dependency(s, "React-performancetimeline")
|
||||
add_dependency(s, "React-rendererdebug")
|
||||
add_dependency(s, "React-rendererconsistency")
|
||||
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
|
||||
add_dependency(s, "React-runtimescheduler")
|
||||
add_dependency(s, "React-RCTAnimation", :framework_name => 'RCTAnimation')
|
||||
add_dependency(s, "React-jsinspector", :framework_name => 'jsinspector_modern')
|
||||
|
||||
@@ -49,6 +49,7 @@ Pod::Spec.new do |s|
|
||||
|
||||
s.dependency "React-Core"
|
||||
s.dependency "React-jsi"
|
||||
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
|
||||
add_dependency(s, "React-jsitooling", :framework_name => "JSITooling")
|
||||
add_dependency(s, "React-jsinspector", :framework_name => 'jsinspector_modern')
|
||||
add_dependency(s, "React-jsinspectorcdp", :framework_name => 'jsinspector_moderncdp')
|
||||
|
||||
@@ -49,6 +49,7 @@ Pod::Spec.new do |s|
|
||||
s.dependency "React-runtimescheduler"
|
||||
s.dependency "React-cxxreact"
|
||||
|
||||
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
|
||||
add_dependency(s, "React-rendererdebug")
|
||||
add_dependency(s, "React-graphics", :additional_framework_paths => ["react/renderer/graphics/platform/ios"])
|
||||
add_dependency(s, "React-utils", :additional_framework_paths => ["react/utils/platform/ios"])
|
||||
|
||||
@@ -39,7 +39,7 @@ Pod::Spec.new do |s|
|
||||
add_dependency(s, "React-jsinspectorcdp", :framework_name => 'jsinspector_moderncdp')
|
||||
add_dependency(s, "React-jsinspectortracing", :framework_name => 'jsinspector_moderntracing')
|
||||
s.dependency "React-callinvoker", version
|
||||
s.dependency "React-runtimeexecutor", version
|
||||
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
|
||||
s.dependency "React-perflogger", version
|
||||
s.dependency "React-jsi", version
|
||||
s.dependency "React-logger", version
|
||||
|
||||
@@ -43,7 +43,7 @@ Pod::Spec.new do |s|
|
||||
s.dependency "React-perflogger", version
|
||||
s.dependency "hermes-engine"
|
||||
s.dependency "React-jsi"
|
||||
s.dependency "React-runtimeexecutor"
|
||||
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
|
||||
|
||||
add_rn_third_party_dependencies(s)
|
||||
end
|
||||
|
||||
@@ -32,6 +32,7 @@ Pod::Spec.new do |s|
|
||||
s.dependency "React-cxxreact", version
|
||||
s.dependency "React-jsi", version
|
||||
s.dependency "React-perflogger", version
|
||||
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
|
||||
add_dependency(s, "React-jsinspector", :framework_name => 'jsinspector_modern')
|
||||
add_dependency(s, "React-jsinspectorcdp", :framework_name => 'jsinspector_moderncdp')
|
||||
add_dependency(s, "React-jsinspectortracing", :framework_name => 'jsinspector_moderntracing')
|
||||
|
||||
@@ -49,7 +49,7 @@ Pod::Spec.new do |s|
|
||||
end
|
||||
|
||||
s.dependency "React-featureflags"
|
||||
s.dependency "React-runtimeexecutor", version
|
||||
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
|
||||
s.dependency "React-jsi"
|
||||
add_dependency(s, "React-jsinspectorcdp", :framework_name => 'jsinspector_moderncdp')
|
||||
add_dependency(s, "React-jsinspectornetwork", :framework_name => 'jsinspector_modernnetwork')
|
||||
|
||||
@@ -40,6 +40,7 @@ Pod::Spec.new do |s|
|
||||
|
||||
s.dependency "React-cxxreact", version
|
||||
s.dependency "React-jsi", version
|
||||
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
|
||||
add_dependency(s, "React-jsinspector", :framework_name => 'jsinspector_modern')
|
||||
add_dependency(s, "React-jsinspectorcdp", :framework_name => 'jsinspector_moderncdp')
|
||||
add_dependency(s, "React-jsinspectortracing", :framework_name => 'jsinspector_moderntracing')
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ Pod::Spec.new do |s|
|
||||
s.dependency "React-cxxreact"
|
||||
s.dependency "React-jsi"
|
||||
s.dependency "React-featureflags"
|
||||
s.dependency "React-runtimeexecutor"
|
||||
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
|
||||
add_dependency(s, "React-featureflags")
|
||||
add_dependency(s, "React-jsinspector", :framework_name => 'jsinspector_modern')
|
||||
add_dependency(s, "React-jsinspectorcdp", :framework_name => 'jsinspector_moderncdp')
|
||||
|
||||
@@ -55,6 +55,7 @@ Pod::Spec.new do |s|
|
||||
s.dependency "ReactCommon/turbomodule/core"
|
||||
s.dependency "React-Fabric"
|
||||
s.dependency "React-FabricComponents"
|
||||
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
|
||||
add_dependency(s, "React-graphics", :additional_framework_paths => ["react/renderer/graphics/platform/ios"])
|
||||
add_dependency(s, "React-RCTFBReactNativeSpec")
|
||||
end
|
||||
|
||||
+1
@@ -52,5 +52,6 @@ Pod::Spec.new do |s|
|
||||
s.dependency "ReactCommon/turbomodule/core"
|
||||
s.dependency "React-runtimescheduler"
|
||||
add_dependency(s, "React-RCTFBReactNativeSpec")
|
||||
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
|
||||
|
||||
end
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ Pod::Spec.new do |s|
|
||||
s.header_mappings_dir = "../../.."
|
||||
end
|
||||
|
||||
s.dependency "React-runtimeexecutor"
|
||||
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
|
||||
s.dependency "React-callinvoker"
|
||||
s.dependency "React-cxxreact"
|
||||
s.dependency "React-rendererdebug"
|
||||
|
||||
+1
@@ -8,6 +8,7 @@
|
||||
#include "RuntimeScheduler_Legacy.h"
|
||||
#include "SchedulerPriorityUtils.h"
|
||||
|
||||
#include <ReactCommon/RuntimeExecutorSyncUIThreadUtils.h>
|
||||
#include <cxxreact/TraceSection.h>
|
||||
#include <react/renderer/consistency/ScopedShadowTreeRevisionLock.h>
|
||||
#include <utility>
|
||||
|
||||
+1
@@ -8,6 +8,7 @@
|
||||
#include "RuntimeScheduler_Modern.h"
|
||||
#include "SchedulerPriorityUtils.h"
|
||||
|
||||
#include <ReactCommon/RuntimeExecutorSyncUIThreadUtils.h>
|
||||
#include <cxxreact/TraceSection.h>
|
||||
#include <jsinspector-modern/tracing/EventLoopReporter.h>
|
||||
#include <react/featureflags/ReactNativeFeatureFlags.h>
|
||||
|
||||
+1
@@ -15,6 +15,7 @@
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <semaphore>
|
||||
#include <thread>
|
||||
#include <variant>
|
||||
|
||||
#include "StubClock.h"
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <ReactCommon/RuntimeExecutor.h>
|
||||
#include <jsi/jsi.h>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
@@ -40,7 +40,7 @@ Pod::Spec.new do |s|
|
||||
|
||||
s.dependency "React-jsiexecutor"
|
||||
s.dependency "React-cxxreact"
|
||||
s.dependency "React-runtimeexecutor"
|
||||
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
|
||||
s.dependency "React-jsi"
|
||||
s.dependency "React-jserrorhandler"
|
||||
s.dependency "React-performancetimeline"
|
||||
|
||||
@@ -48,6 +48,7 @@ Pod::Spec.new do |s|
|
||||
|
||||
s.dependency "React-hermes"
|
||||
s.dependency "hermes-engine"
|
||||
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
|
||||
add_dependency(s, "React-jsitooling", :framework_name => "JSITooling")
|
||||
|
||||
add_rn_third_party_dependencies(s)
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ Pod::Spec.new do |s|
|
||||
s.dependency "React-jsiexecutor"
|
||||
s.dependency "React-cxxreact"
|
||||
s.dependency "React-callinvoker"
|
||||
s.dependency "React-runtimeexecutor"
|
||||
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
|
||||
s.dependency "React-runtimescheduler"
|
||||
s.dependency "React-jsi"
|
||||
s.dependency "React-Core/Default"
|
||||
|
||||
@@ -8,11 +8,11 @@ set(CMAKE_VERBOSE_MAKEFILE on)
|
||||
|
||||
include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
|
||||
|
||||
file(GLOB_RECURSE runtimeexecutor_SRC CONFIGURE_DEPENDS *.cpp *.h)
|
||||
file(GLOB_RECURSE runtimeexecutor_SRC CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ReactCommon/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/platform/cxx/*.cpp)
|
||||
|
||||
add_library(runtimeexecutor OBJECT ${runtimeexecutor_SRC})
|
||||
|
||||
target_include_directories(runtimeexecutor PUBLIC .)
|
||||
target_include_directories(runtimeexecutor PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/platform/cxx)
|
||||
|
||||
target_link_libraries(runtimeexecutor jsi)
|
||||
target_compile_reactnative_options(runtimeexecutor PRIVATE)
|
||||
|
||||
@@ -17,7 +17,12 @@ else
|
||||
end
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
header_search_paths = [
|
||||
"\"$(PODS_TARGET_SRCROOT)\"",
|
||||
]
|
||||
|
||||
s.name = "React-runtimeexecutor"
|
||||
s.module_name = "React_runtimeexecutor"
|
||||
s.version = version
|
||||
s.summary = "-" # TODO
|
||||
s.homepage = "https://reactnative.dev/"
|
||||
@@ -25,8 +30,18 @@ Pod::Spec.new do |s|
|
||||
s.author = "Meta Platforms, Inc. and its affiliates"
|
||||
s.platforms = min_supported_versions
|
||||
s.source = source
|
||||
s.source_files = "**/*.{cpp,h}"
|
||||
s.source_files = "ReactCommon/*.{m,mm,cpp,h}", "platform/ios/**/*.{m,mm,cpp,h}"
|
||||
s.header_dir = "ReactCommon"
|
||||
|
||||
if ENV['USE_FRAMEWORKS']
|
||||
s.header_mappings_dir = '.'
|
||||
header_search_paths = header_search_paths + ["\"$(PODS_TARGET_SRCROOT)/platform/ios\""]
|
||||
end
|
||||
|
||||
s.pod_target_xcconfig = { "USE_HEADERMAP" => "NO",
|
||||
"CLANG_CXX_LANGUAGE_STANDARD" => rct_cxx_language_standard(),
|
||||
"HEADER_SEARCH_PATHS" => header_search_paths.join(' '),
|
||||
"DEFINES_MODULE" => "YES" }
|
||||
|
||||
s.dependency "React-jsi", version
|
||||
end
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <future>
|
||||
#include <thread>
|
||||
|
||||
#include <jsi/jsi.h>
|
||||
|
||||
namespace facebook::react {
|
||||
@@ -25,63 +22,4 @@ namespace facebook::react {
|
||||
using RuntimeExecutor =
|
||||
std::function<void(std::function<void(jsi::Runtime& runtime)>&& callback)>;
|
||||
|
||||
/*
|
||||
* Schedules `runtimeWork` to be executed on the same thread using the
|
||||
* `RuntimeExecutor`, and blocks on its completion.
|
||||
*
|
||||
* Example:
|
||||
* - [UI thread] Schedule `runtimeCaptureBlock` on js thread
|
||||
* - [UI thread] Wait for runtime capture: await(runtime)
|
||||
* - [JS thread] Capture runtime for ui thread: resolve(runtime, &rt);
|
||||
* - [JS thread] Wait until runtimeWork done: await(runtimeWorkDone)
|
||||
* - [UI thread] Call runtimeWork: runtimeWork(*runtimePrt);
|
||||
* - [UI thread] Signal runtimeWork done: resolve(runtimeWorkDone)
|
||||
* - [UI thread] Wait until runtime capture block finished:
|
||||
* await(runtimeCaptureBlockDone);
|
||||
* - [JS thread] Signal runtime capture block is finished:
|
||||
* resolve(runtimeCaptureBlockDone);
|
||||
*/
|
||||
inline static void executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
const RuntimeExecutor& runtimeExecutor,
|
||||
std::function<void(jsi::Runtime&)>&& runtimeWork) {
|
||||
std::promise<jsi::Runtime*> runtime;
|
||||
std::promise<void> runtimeCaptureBlockDone;
|
||||
std::promise<void> runtimeWorkDone;
|
||||
|
||||
auto callingThread = std::this_thread::get_id();
|
||||
|
||||
auto runtimeCaptureBlock = [&](jsi::Runtime& rt) {
|
||||
runtime.set_value(&rt);
|
||||
|
||||
auto runtimeThread = std::this_thread::get_id();
|
||||
if (callingThread != runtimeThread) {
|
||||
// Block `runtimeThread` on execution of `runtimeWork` on `callingThread`.
|
||||
runtimeWorkDone.get_future().wait();
|
||||
}
|
||||
|
||||
// TODO(T225331233): This is likely unnecessary. Remove it.
|
||||
runtimeCaptureBlockDone.set_value();
|
||||
};
|
||||
runtimeExecutor(std::move(runtimeCaptureBlock));
|
||||
|
||||
jsi::Runtime* runtimePtr = runtime.get_future().get();
|
||||
runtimeWork(*runtimePtr);
|
||||
runtimeWorkDone.set_value();
|
||||
|
||||
// TODO(T225331233): This is likely unnecessary. Remove it.
|
||||
runtimeCaptureBlockDone.get_future().wait();
|
||||
}
|
||||
|
||||
template <typename DataT>
|
||||
inline static DataT executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
const RuntimeExecutor& runtimeExecutor,
|
||||
std::function<DataT(jsi::Runtime& runtime)>&& runtimeWork) {
|
||||
DataT data;
|
||||
|
||||
executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
runtimeExecutor,
|
||||
[&](jsi::Runtime& runtime) { data = runtimeWork(runtime); });
|
||||
|
||||
return data;
|
||||
}
|
||||
} // namespace facebook::react
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include <ReactCommon/RuntimeExecutorSyncUIThreadUtils.h>
|
||||
#include <future>
|
||||
#include <thread>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
/*
|
||||
* Schedules `runtimeWork` to be executed on the same thread using the
|
||||
* `RuntimeExecutor`, and blocks on its completion.
|
||||
*
|
||||
* Example:
|
||||
* - [UI thread] Schedule `runtimeCaptureBlock` on js thread
|
||||
* - [UI thread] Wait for runtime capture: await(runtime)
|
||||
* - [JS thread] Capture runtime for ui thread: resolve(runtime, &rt);
|
||||
* - [JS thread] Wait until runtimeWork done: await(runtimeWorkDone)
|
||||
* - [UI thread] Call runtimeWork: runtimeWork(*runtimePrt);
|
||||
* - [UI thread] Signal runtimeWork done: resolve(runtimeWorkDone)
|
||||
* - [UI thread] Wait until runtime capture block finished:
|
||||
* await(runtimeCaptureBlockDone);
|
||||
* - [JS thread] Signal runtime capture block is finished:
|
||||
* resolve(runtimeCaptureBlockDone);
|
||||
*/
|
||||
void executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
const RuntimeExecutor& runtimeExecutor,
|
||||
std::function<void(jsi::Runtime&)>&& runtimeWork) {
|
||||
std::promise<jsi::Runtime*> runtime;
|
||||
std::promise<void> runtimeCaptureBlockDone;
|
||||
std::promise<void> runtimeWorkDone;
|
||||
|
||||
auto callingThread = std::this_thread::get_id();
|
||||
|
||||
auto runtimeCaptureBlock = [&](jsi::Runtime& rt) {
|
||||
runtime.set_value(&rt);
|
||||
|
||||
auto runtimeThread = std::this_thread::get_id();
|
||||
if (callingThread != runtimeThread) {
|
||||
// Block `runtimeThread` on execution of `runtimeWork` on `callingThread`.
|
||||
runtimeWorkDone.get_future().wait();
|
||||
}
|
||||
|
||||
// TODO(T225331233): This is likely unnecessary. Remove it.
|
||||
runtimeCaptureBlockDone.set_value();
|
||||
};
|
||||
runtimeExecutor(std::move(runtimeCaptureBlock));
|
||||
|
||||
jsi::Runtime* runtimePtr = runtime.get_future().get();
|
||||
runtimeWork(*runtimePtr);
|
||||
runtimeWorkDone.set_value();
|
||||
|
||||
// TODO(T225331233): This is likely unnecessary. Remove it.
|
||||
runtimeCaptureBlockDone.get_future().wait();
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ReactCommon/RuntimeExecutor.h>
|
||||
|
||||
#include <jsi/jsi.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
/*
|
||||
* Schedules `runtimeWork` to be executed on the same thread using the
|
||||
* `RuntimeExecutor`, and blocks on its completion.
|
||||
*/
|
||||
void executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
const RuntimeExecutor& runtimeExecutor,
|
||||
std::function<void(jsi::Runtime&)>&& runtimeWork);
|
||||
|
||||
template <typename DataT>
|
||||
inline static DataT executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
const RuntimeExecutor& runtimeExecutor,
|
||||
std::function<DataT(jsi::Runtime& runtime)>&& runtimeWork) {
|
||||
DataT data;
|
||||
|
||||
executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
runtimeExecutor,
|
||||
[&](jsi::Runtime& runtime) { data = runtimeWork(runtime); });
|
||||
|
||||
return data;
|
||||
}
|
||||
} // namespace facebook::react
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ReactCommon/RuntimeExecutor.h>
|
||||
|
||||
#include <jsi/jsi.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
/*
|
||||
* Schedules `runtimeWork` to be executed on the same thread using the
|
||||
* `RuntimeExecutor`, and blocks on its completion.
|
||||
*/
|
||||
void executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
const RuntimeExecutor& runtimeExecutor,
|
||||
std::function<void(jsi::Runtime&)>&& runtimeWork);
|
||||
|
||||
template <typename DataT>
|
||||
inline static DataT executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
const RuntimeExecutor& runtimeExecutor,
|
||||
std::function<DataT(jsi::Runtime& runtime)>&& runtimeWork) {
|
||||
DataT data;
|
||||
|
||||
executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
runtimeExecutor,
|
||||
[&](jsi::Runtime& runtime) { data = runtimeWork(runtime); });
|
||||
|
||||
return data;
|
||||
}
|
||||
} // namespace facebook::react
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <ReactCommon/RuntimeExecutorSyncUIThreadUtils.h>
|
||||
#include <future>
|
||||
#include <thread>
|
||||
|
||||
namespace facebook::react {
|
||||
/*
|
||||
* Schedules `runtimeWork` to be executed on the same thread using the
|
||||
* `RuntimeExecutor`, and blocks on its completion.
|
||||
*
|
||||
* Example:
|
||||
* - [UI thread] Schedule `runtimeCaptureBlock` on js thread
|
||||
* - [UI thread] Wait for runtime capture: await(runtime)
|
||||
* - [JS thread] Capture runtime for ui thread: resolve(runtime, &rt);
|
||||
* - [JS thread] Wait until runtimeWork done: await(runtimeWorkDone)
|
||||
* - [UI thread] Call runtimeWork: runtimeWork(*runtimePrt);
|
||||
* - [UI thread] Signal runtimeWork done: resolve(runtimeWorkDone)
|
||||
* - [UI thread] Wait until runtime capture block finished:
|
||||
* await(runtimeCaptureBlockDone);
|
||||
* - [JS thread] Signal runtime capture block is finished:
|
||||
* resolve(runtimeCaptureBlockDone);
|
||||
*/
|
||||
void executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
const RuntimeExecutor &runtimeExecutor,
|
||||
std::function<void(jsi::Runtime &)> &&runtimeWork)
|
||||
{
|
||||
std::promise<jsi::Runtime *> runtime;
|
||||
std::promise<void> runtimeCaptureBlockDone;
|
||||
std::promise<void> runtimeWorkDone;
|
||||
|
||||
auto callingThread = std::this_thread::get_id();
|
||||
|
||||
auto runtimeCaptureBlock = [&](jsi::Runtime &rt) {
|
||||
runtime.set_value(&rt);
|
||||
|
||||
auto runtimeThread = std::this_thread::get_id();
|
||||
if (callingThread != runtimeThread) {
|
||||
// Block `runtimeThread` on execution of `runtimeWork` on `callingThread`.
|
||||
runtimeWorkDone.get_future().wait();
|
||||
}
|
||||
|
||||
// TODO(T225331233): This is likely unnecessary. Remove it.
|
||||
runtimeCaptureBlockDone.set_value();
|
||||
};
|
||||
runtimeExecutor(std::move(runtimeCaptureBlock));
|
||||
|
||||
jsi::Runtime *runtimePtr = runtime.get_future().get();
|
||||
runtimeWork(*runtimePtr);
|
||||
runtimeWorkDone.set_value();
|
||||
|
||||
// TODO(T225331233): This is likely unnecessary. Remove it.
|
||||
runtimeCaptureBlockDone.get_future().wait();
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
Reference in New Issue
Block a user