diff --git a/React/Fabric/RCTScheduler.mm b/React/Fabric/RCTScheduler.mm index d7e81c4254b..8af8a92cd73 100644 --- a/React/Fabric/RCTScheduler.mm +++ b/React/Fabric/RCTScheduler.mm @@ -58,8 +58,8 @@ private: SharedContextContainer contextContainer = std::make_shared(); - EventBeatFactory synchronousBeatFactory = []() { - return std::make_unique(); + EventBeatFactory synchronousBeatFactory = [bridge]() { + return std::make_unique(bridge.jsMessageThread); }; EventBeatFactory asynchronousBeatFactory = [bridge]() { diff --git a/React/Fabric/Utils/MainRunLoopEventBeat.h b/React/Fabric/Utils/MainRunLoopEventBeat.h index 8bf0aea8b47..abfd8c2300f 100644 --- a/React/Fabric/Utils/MainRunLoopEventBeat.h +++ b/React/Fabric/Utils/MainRunLoopEventBeat.h @@ -7,6 +7,7 @@ #include #include +#include #include namespace facebook { @@ -20,12 +21,15 @@ class MainRunLoopEventBeat final: public EventBeat { public: - MainRunLoopEventBeat(); + MainRunLoopEventBeat(std::shared_ptr messageQueueThread); ~MainRunLoopEventBeat(); void induce() const override; private: + void blockMessageQueueAndThenBeat() const; + + std::shared_ptr messageQueueThread_; CFRunLoopObserverRef mainRunLoopObserver_; }; diff --git a/React/Fabric/Utils/MainRunLoopEventBeat.mm b/React/Fabric/Utils/MainRunLoopEventBeat.mm index dcf67c7a167..33e8e9a38eb 100644 --- a/React/Fabric/Utils/MainRunLoopEventBeat.mm +++ b/React/Fabric/Utils/MainRunLoopEventBeat.mm @@ -5,12 +5,15 @@ #import "MainRunLoopEventBeat.h" +#import #import namespace facebook { namespace react { -MainRunLoopEventBeat::MainRunLoopEventBeat() { +MainRunLoopEventBeat::MainRunLoopEventBeat(std::shared_ptr messageQueueThread): + messageQueueThread_(std::move(messageQueueThread)) { + mainRunLoopObserver_ = CFRunLoopObserverCreateWithHandler( NULL /* allocator */, @@ -18,7 +21,11 @@ MainRunLoopEventBeat::MainRunLoopEventBeat() { true /* repeats */, 0 /* order */, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { - this->beat(); + if (!this->isRequested_) { + return; + } + + this->blockMessageQueueAndThenBeat(); } ); @@ -38,9 +45,33 @@ void MainRunLoopEventBeat::induce() const { } RCTExecuteOnMainQueue(^{ - this->beat(); + this->blockMessageQueueAndThenBeat(); }); } +void MainRunLoopEventBeat::blockMessageQueueAndThenBeat() const { + // Note: We need the third mutex to get back to the main thread before + // the lambda is finished (because all mutexes are allocated on the stack). + + std::mutex mutex1; + std::mutex mutex2; + std::mutex mutex3; + + mutex1.lock(); + mutex2.lock(); + mutex3.lock(); + + messageQueueThread_->runOnQueue([&]() { + mutex1.unlock(); + mutex2.lock(); + mutex3.unlock(); + }); + + mutex1.lock(); + beat(); + mutex2.unlock(); + mutex3.lock(); +} + } // namespace react } // namespace facebook