introduce EventEmitter::experimental_flushSync (#43592)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/43592

changelog: [internal]

Exposing experimental API EventEmitter::experimental_flushSync to trigger synchronous event from native. The API will be changed in the future, this is exposed only for experimentation.

Reviewed By: javache

Differential Revision: D54805494

fbshipit-source-id: fb395588cf1dc944a920ec4a2257390552850263
This commit is contained in:
Samuel Susla
2024-03-22 02:33:16 -07:00
committed by Facebook GitHub Bot
parent 15a5638c62
commit 223e6dc898
6 changed files with 68 additions and 8 deletions
@@ -18,9 +18,12 @@ namespace facebook::react {
EventDispatcher::EventDispatcher(
const EventQueueProcessor& eventProcessor,
const EventBeat::Factory& asynchronousEventBeatFactory,
const EventBeat::SharedOwnerBox& ownerBox)
: eventQueue_(
EventQueue(eventProcessor, asynchronousEventBeatFactory(ownerBox))) {}
const EventBeat::SharedOwnerBox& ownerBox,
RuntimeScheduler& runtimeScheduler)
: eventQueue_(EventQueue(
eventProcessor,
asynchronousEventBeatFactory(ownerBox),
runtimeScheduler)) {}
void EventDispatcher::dispatchEvent(RawEvent&& rawEvent) const {
// Allows the event listener to interrupt default event dispatch
@@ -35,6 +38,10 @@ void EventDispatcher::dispatchEvent(RawEvent&& rawEvent) const {
eventQueue_.enqueueEvent(std::move(rawEvent));
}
void EventDispatcher::experimental_flushSync() const {
eventQueue_.experimental_flushSync();
}
void EventDispatcher::dispatchStateUpdate(StateUpdate&& stateUpdate) const {
eventQueue_.enqueueStateUpdate(std::move(stateUpdate));
}
@@ -16,6 +16,7 @@
namespace facebook::react {
struct RawEvent;
class RuntimeScheduler;
/*
* Represents event-delivery infrastructure.
@@ -29,13 +30,19 @@ class EventDispatcher {
EventDispatcher(
const EventQueueProcessor& eventProcessor,
const EventBeat::Factory& asynchronousEventBeatFactory,
const EventBeat::SharedOwnerBox& ownerBox);
const EventBeat::SharedOwnerBox& ownerBox,
RuntimeScheduler& runtimeScheduler);
/*
* Dispatches a raw event with given priority using event-delivery pipe.
*/
void dispatchEvent(RawEvent&& rawEvent) const;
/*
* Experimental API exposed to support EventEmitter::experimental_flushSync.
*/
void experimental_flushSync() const;
/*
* Dispatches a raw event with asynchronous batched priority. Before the
* dispatch we make sure that no other RawEvent of same type and same target
@@ -57,6 +57,20 @@ class EventEmitter {
const SharedEventTarget& getEventTarget() const;
/*
* Experimental API that will change in the future.
*/
template <typename Lambda>
void experimental_flushSync(Lambda syncFunc) const {
auto eventDispatcher = eventDispatcher_.lock();
if (!eventDispatcher) {
return;
}
syncFunc();
eventDispatcher->experimental_flushSync();
}
/*
* Initiates an event delivery process.
* Is used by particular subclasses only.
@@ -7,6 +7,7 @@
#include "EventQueue.h"
#include <react/renderer/runtimescheduler/RuntimeScheduler.h>
#include "EventEmitter.h"
#include "ShadowNodeFamily.h"
@@ -14,9 +15,11 @@ namespace facebook::react {
EventQueue::EventQueue(
EventQueueProcessor eventProcessor,
std::unique_ptr<EventBeat> eventBeat)
std::unique_ptr<EventBeat> eventBeat,
RuntimeScheduler& runtimeScheduler)
: eventProcessor_(std::move(eventProcessor)),
eventBeat_(std::move(eventBeat)) {
eventBeat_(std::move(eventBeat)),
runtimeScheduler_(&runtimeScheduler) {
eventBeat_->setBeatCallback(
[this](jsi::Runtime& runtime) { onBeat(runtime); });
}
@@ -76,10 +79,26 @@ void EventQueue::enqueueStateUpdate(StateUpdate&& stateUpdate) const {
}
void EventQueue::onEnqueue() const {
if (synchronousAccessRequested_) {
// Sync flush has been scheduled, no need to request access to the runtime.
return;
}
eventBeat_->request();
}
void EventQueue::experimental_flushSync() const {
synchronousAccessRequested_ = true;
runtimeScheduler_->executeNowOnTheSameThread([this](jsi::Runtime& runtime) {
synchronousAccessRequested_ = false;
onBeat(runtime);
});
}
void EventQueue::onBeat(jsi::Runtime& runtime) const {
if (synchronousAccessRequested_) {
// Sync flush has been scheduled, let's yield to it.
return;
}
flushStateUpdates();
flushEvents(runtime);
}
@@ -19,6 +19,8 @@
namespace facebook::react {
class RuntimeScheduler;
/*
* Event Queue synchronized with given Event Beat and dispatching event
* using given Event Pipe.
@@ -27,7 +29,8 @@ class EventQueue {
public:
EventQueue(
EventQueueProcessor eventProcessor,
std::unique_ptr<EventBeat> eventBeat);
std::unique_ptr<EventBeat> eventBeat,
RuntimeScheduler& runtimeScheduler);
/*
* Enqueues and (probably later) dispatch a given event.
@@ -48,6 +51,11 @@ class EventQueue {
*/
void enqueueStateUpdate(StateUpdate&& stateUpdate) const;
/*
* Experimental API exposed to support EventEmitter::experimental_flushSync.
*/
void experimental_flushSync() const;
protected:
/*
* Called on any enqueue operation.
@@ -67,6 +75,10 @@ class EventQueue {
mutable std::vector<RawEvent> eventQueue_;
mutable std::vector<StateUpdate> stateUpdateQueue_;
mutable std::mutex queueMutex_;
// TODO: T183075253
RuntimeScheduler* runtimeScheduler_;
mutable std::atomic_bool synchronousAccessRequested_{false};
};
} // namespace facebook::react
@@ -84,7 +84,8 @@ Scheduler::Scheduler(
eventDispatcher_->emplace(
EventQueueProcessor(eventPipe, eventPipeConclusion, statePipe),
schedulerToolbox.asynchronousEventBeatFactory,
eventOwnerBox);
eventOwnerBox,
*runtimeScheduler);
// Casting to `std::shared_ptr<EventDispatcher const>`.
auto eventDispatcher =