Files
react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler.cpp
T
Samuel Susla fcda1ac514 Add support for synchronous completeRoot
Summary:
changelog: [internal]

Exposes a new flag on RuntimeScheduler: `unstable_getIsSynchronous`. Flag indicates if the current code is run synchronously and therefore commit phase should be synchronous.

Unit tests will be added later, to keep this diff short. This code path is not executed yet.

Reviewed By: mdvacca, ShikaSD

Differential Revision: D32677814

fbshipit-source-id: e01d4fff7e716d627ff99fe104965851138c3aef
2021-12-07 12:11:24 -08:00

146 lines
4.1 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "RuntimeScheduler.h"
#include "ErrorUtils.h"
namespace facebook {
namespace react {
#pragma mark - Public
RuntimeScheduler::RuntimeScheduler(
RuntimeExecutor const &runtimeExecutor,
std::function<RuntimeSchedulerTimePoint()> now)
: runtimeExecutor_(runtimeExecutor), now_(now) {}
void RuntimeScheduler::scheduleWork(
std::function<void(jsi::Runtime &)> callback) const {
if (enableYielding_) {
shouldYield_ = true;
runtimeExecutor_(
[this, callback = std::move(callback)](jsi::Runtime &runtime) {
shouldYield_ = false;
callback(runtime);
startWorkLoop(runtime);
});
} else {
runtimeExecutor_([callback = std::move(callback)](jsi::Runtime &runtime) {
callback(runtime);
});
}
}
std::shared_ptr<Task> RuntimeScheduler::scheduleTask(
SchedulerPriority priority,
jsi::Function callback) {
auto expirationTime = now() + timeoutForSchedulerPriority(priority);
auto task =
std::make_shared<Task>(priority, std::move(callback), expirationTime);
taskQueue_.push(task);
if (!isCallbackScheduled_ && !isPerformingWork_) {
isCallbackScheduled_ = true;
runtimeExecutor_([this](jsi::Runtime &runtime) {
isCallbackScheduled_ = false;
startWorkLoop(runtime);
});
}
return task;
}
bool RuntimeScheduler::getShouldYield() const noexcept {
return shouldYield_;
}
bool RuntimeScheduler::getIsSynchronous() const noexcept {
return isSynchronous_;
}
void RuntimeScheduler::cancelTask(const std::shared_ptr<Task> &task) noexcept {
task->callback.reset();
}
SchedulerPriority RuntimeScheduler::getCurrentPriorityLevel() const noexcept {
return currentPriority_;
}
RuntimeSchedulerTimePoint RuntimeScheduler::now() const noexcept {
return now_();
}
void RuntimeScheduler::setEnableYielding(bool enableYielding) {
enableYielding_ = enableYielding;
}
void RuntimeScheduler::executeNowOnTheSameThread(
std::function<void(jsi::Runtime &runtime)> callback) {
shouldYield_ = true;
executeSynchronouslyOnSameThread_CAN_DEADLOCK(
runtimeExecutor_,
[this, callback = std::move(callback)](jsi::Runtime &runtime) {
shouldYield_ = false;
auto task = jsi::Function::createFromHostFunction(
runtime,
jsi::PropNameID::forUtf8(runtime, ""),
3,
[callback = std::move(callback)](
jsi::Runtime &runtime,
jsi::Value const &,
jsi::Value const *arguments,
size_t) -> jsi::Value {
callback(runtime);
return jsi::Value::undefined();
});
assert(!isPerformingWork_);
this->scheduleTask(
SchedulerPriority::ImmediatePriority, std::move(task));
isSynchronous_ = true;
startWorkLoop(runtime);
isSynchronous_ = false;
});
}
#pragma mark - Private
void RuntimeScheduler::startWorkLoop(jsi::Runtime &runtime) const {
auto previousPriority = currentPriority_;
isPerformingWork_ = true;
try {
while (!taskQueue_.empty()) {
auto topPriorityTask = taskQueue_.top();
auto now = now_();
auto didUserCallbackTimeout = topPriorityTask->expirationTime <= now;
if (!didUserCallbackTimeout && shouldYield_) {
// This task hasn't expired and we need to yield.
break;
}
currentPriority_ = topPriorityTask->priority;
auto result = topPriorityTask->execute(runtime);
if (result.isObject() && result.getObject(runtime).isFunction(runtime)) {
topPriorityTask->callback =
result.getObject(runtime).getFunction(runtime);
} else {
if (taskQueue_.top() == topPriorityTask) {
taskQueue_.pop();
}
}
}
} catch (jsi::JSError &error) {
handleFatalError(runtime, error);
}
currentPriority_ = previousPriority;
isPerformingWork_ = false;
}
} // namespace react
} // namespace facebook