Fabric: Proper thread synchronization in MainRunLoopEventBeat
Summary: To dispatch events synchonously on the main thread we still have to block the Message Queue. We actually dispatch events on the Message Queue while the main thread is waiting. Reviewed By: mdvacca Differential Revision: D9799853 fbshipit-source-id: 8033be36f27371ad2f1dc7210d564fbca1174910
This commit is contained in:
parent
238dec2787
commit
4eb9b40979
|
@ -58,8 +58,8 @@ private:
|
|||
|
||||
SharedContextContainer contextContainer = std::make_shared<ContextContainer>();
|
||||
|
||||
EventBeatFactory synchronousBeatFactory = []() {
|
||||
return std::make_unique<MainRunLoopEventBeat>();
|
||||
EventBeatFactory synchronousBeatFactory = [bridge]() {
|
||||
return std::make_unique<MainRunLoopEventBeat>(bridge.jsMessageThread);
|
||||
};
|
||||
|
||||
EventBeatFactory asynchronousBeatFactory = [bridge]() {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <CoreFoundation/CFRunLoop.h>
|
||||
#include <cxxreact/MessageQueueThread.h>
|
||||
#include <fabric/events/EventBeat.h>
|
||||
|
||||
namespace facebook {
|
||||
|
@ -20,12 +21,15 @@ class MainRunLoopEventBeat final:
|
|||
public EventBeat {
|
||||
|
||||
public:
|
||||
MainRunLoopEventBeat();
|
||||
MainRunLoopEventBeat(std::shared_ptr<MessageQueueThread> messageQueueThread);
|
||||
~MainRunLoopEventBeat();
|
||||
|
||||
void induce() const override;
|
||||
|
||||
private:
|
||||
void blockMessageQueueAndThenBeat() const;
|
||||
|
||||
std::shared_ptr<MessageQueueThread> messageQueueThread_;
|
||||
CFRunLoopObserverRef mainRunLoopObserver_;
|
||||
};
|
||||
|
||||
|
|
|
@ -5,12 +5,15 @@
|
|||
|
||||
#import "MainRunLoopEventBeat.h"
|
||||
|
||||
#import <mutex>
|
||||
#import <React/RCTUtils.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
MainRunLoopEventBeat::MainRunLoopEventBeat() {
|
||||
MainRunLoopEventBeat::MainRunLoopEventBeat(std::shared_ptr<MessageQueueThread> 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
|
||||
|
|
Loading…
Reference in New Issue