diff --git a/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.cpp b/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.cpp index be243532f79..693e6820811 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.cpp @@ -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)); } diff --git a/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.h b/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.h index c243100f66f..b974e5e6ea0 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.h +++ b/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.h @@ -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 diff --git a/packages/react-native/ReactCommon/react/renderer/core/EventEmitter.h b/packages/react-native/ReactCommon/react/renderer/core/EventEmitter.h index 04bb9ebe42c..e078a95f7e6 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/EventEmitter.h +++ b/packages/react-native/ReactCommon/react/renderer/core/EventEmitter.h @@ -57,6 +57,20 @@ class EventEmitter { const SharedEventTarget& getEventTarget() const; + /* + * Experimental API that will change in the future. + */ + template + 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. diff --git a/packages/react-native/ReactCommon/react/renderer/core/EventQueue.cpp b/packages/react-native/ReactCommon/react/renderer/core/EventQueue.cpp index cef50c68380..4643e5dea27 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/EventQueue.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/EventQueue.cpp @@ -7,6 +7,7 @@ #include "EventQueue.h" +#include #include "EventEmitter.h" #include "ShadowNodeFamily.h" @@ -14,9 +15,11 @@ namespace facebook::react { EventQueue::EventQueue( EventQueueProcessor eventProcessor, - std::unique_ptr eventBeat) + std::unique_ptr 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); } diff --git a/packages/react-native/ReactCommon/react/renderer/core/EventQueue.h b/packages/react-native/ReactCommon/react/renderer/core/EventQueue.h index 76316cce668..f82940c431f 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/EventQueue.h +++ b/packages/react-native/ReactCommon/react/renderer/core/EventQueue.h @@ -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); + std::unique_ptr 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 eventQueue_; mutable std::vector stateUpdateQueue_; mutable std::mutex queueMutex_; + + // TODO: T183075253 + RuntimeScheduler* runtimeScheduler_; + mutable std::atomic_bool synchronousAccessRequested_{false}; }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp index b41d38c028f..908e01904dd 100644 --- a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp +++ b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp @@ -84,7 +84,8 @@ Scheduler::Scheduler( eventDispatcher_->emplace( EventQueueProcessor(eventPipe, eventPipeConclusion, statePipe), schedulerToolbox.asynchronousEventBeatFactory, - eventOwnerBox); + eventOwnerBox, + *runtimeScheduler); // Casting to `std::shared_ptr`. auto eventDispatcher =