Skip to content

Commit

Permalink
Add minimal implementation of RuntimeScheduler::scheduleTask
Browse files Browse the repository at this point in the history
Summary:
Changelog: [internal]

Add minimal implementation of schedule task. More features and proper scheduling will be added later.

Reviewed By: mdvacca

Differential Revision: D27622138

fbshipit-source-id: b2e4623d38e7217290a6a3c59ccc10a1c13e3a4f
  • Loading branch information
sammy-SC authored and facebook-github-bot committed Apr 13, 2021
1 parent 71b5178 commit 2779129
Show file tree
Hide file tree
Showing 9 changed files with 160 additions and 12 deletions.
1 change: 1 addition & 0 deletions ReactCommon/react/renderer/runtimescheduler/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,6 @@ rn_xplat_cxx_library(
visibility = ["PUBLIC"],
deps = [
react_native_xplat_target("runtimeexecutor:runtimeexecutor"),
react_native_xplat_target("react/renderer/debug:debug"),
],
)
17 changes: 16 additions & 1 deletion ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,19 @@

#include "RuntimeScheduler.h"

namespace facebook::react {} // namespace facebook::react
namespace facebook::react {

RuntimeScheduler::RuntimeScheduler(RuntimeExecutor const &runtimeExecutor)
: runtimeExecutor_(runtimeExecutor) {}

void RuntimeScheduler::scheduleTask(std::shared_ptr<Task> const &task) {
taskQueue_.push(task);

runtimeExecutor_([this](jsi::Runtime &runtime) {
auto topPriority = taskQueue_.top();
taskQueue_.pop();
(*topPriority)(runtime);
});
}

} // namespace facebook::react
26 changes: 21 additions & 5 deletions ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,26 @@

#pragma once

namespace facebook {
namespace react {
#include <ReactCommon/RuntimeExecutor.h>
#include <react/renderer/runtimescheduler/Task.h>
#include <memory>
#include <queue>

class RuntimeScheduler final {};
namespace facebook::react {

} // namespace react
} // namespace facebook
class RuntimeScheduler final {
public:
RuntimeScheduler(RuntimeExecutor const &runtimeExecutor);

void scheduleTask(std::shared_ptr<Task> const &task);

private:
mutable std::priority_queue<
std::shared_ptr<Task>,
std::vector<std::shared_ptr<Task>>,
TaskPriorityComparer>
taskQueue_;
RuntimeExecutor const runtimeExecutor_;
};

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,24 @@
#include "RuntimeSchedulerBinding.h"
#include "SchedulerPriority.h"

#include <react/debug/react_native_assert.h>
#include <memory>

namespace facebook::react {

std::shared_ptr<RuntimeSchedulerBinding>
RuntimeSchedulerBinding::createAndInstallIfNeeded(jsi::Runtime &runtime) {
RuntimeSchedulerBinding::createAndInstallIfNeeded(
jsi::Runtime &runtime,
RuntimeExecutor runtimeExecutor) {
auto runtimeSchedulerModuleName = "nativeRuntimeScheduler";

auto runtimeSchedulerValue =
runtime.global().getProperty(runtime, runtimeSchedulerModuleName);
if (runtimeSchedulerValue.isUndefined()) {
// The global namespace does not have an instance of the binding;
// we need to create, install and return it.
auto runtimeSchedulerBinding = std::make_shared<RuntimeSchedulerBinding>();
auto runtimeSchedulerBinding = std::make_shared<RuntimeSchedulerBinding>(
RuntimeScheduler(runtimeExecutor));
auto object =
jsi::Object::createFromHostObject(runtime, runtimeSchedulerBinding);
runtime.global().setProperty(
Expand All @@ -35,11 +39,37 @@ RuntimeSchedulerBinding::createAndInstallIfNeeded(jsi::Runtime &runtime) {
return runtimeSchedulerObject.getHostObject<RuntimeSchedulerBinding>(runtime);
}

RuntimeSchedulerBinding::RuntimeSchedulerBinding(
RuntimeScheduler runtimeScheduler)
: runtimeScheduler_(std::move(runtimeScheduler)) {}

jsi::Value RuntimeSchedulerBinding::get(
jsi::Runtime &runtime,
jsi::PropNameID const &name) {
auto propertyName = name.utf8(runtime);

if (propertyName == "unstable_scheduleCallback") {
return jsi::Function::createFromHostFunction(
runtime,
name,
3,
[this](
jsi::Runtime &runtime,
jsi::Value const &,
jsi::Value const *arguments,
size_t) noexcept -> jsi::Value {
SchedulerPriority priority = fromRawValue(arguments[0].getNumber());
auto callback = arguments[1].getObject(runtime).getFunction(runtime);
react_native_assert(arguments[2].isUndefined());

auto task = std::make_shared<Task>(priority, std::move(callback));
runtimeScheduler_.scheduleTask(task);

// TODO: return reference to the task.
return jsi::Value::undefined();
});
}

if (propertyName == "unstable_ImmediatePriority") {
return jsi::Value(runtime, serialize(SchedulerPriority::ImmediatePriority));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#pragma once

#include <jsi/jsi.h>
#include <react/renderer/runtimescheduler/RuntimeScheduler.h>

namespace facebook::react {

Expand All @@ -16,20 +17,25 @@ namespace facebook::react {
*/
class RuntimeSchedulerBinding : public jsi::HostObject {
public:
RuntimeSchedulerBinding(RuntimeScheduler runtimeScheduler);

/*
* Installs RuntimeSchedulerBinding into JavaScript runtime if needed.
* Creates and sets `RuntimeSchedulerBinding` into the global namespace.
* In case if the global namespace already has a `RuntimeSchedulerBinding`
* installed, returns that. Thread synchronization must be enforced
* externally.
* installed, returns that.
*/
static std::shared_ptr<RuntimeSchedulerBinding> createAndInstallIfNeeded(
jsi::Runtime &runtime);
jsi::Runtime &runtime,
RuntimeExecutor runtimeExecutor);

/*
* `jsi::HostObject` specific overloads.
*/
jsi::Value get(jsi::Runtime &runtime, jsi::PropNameID const &name) override;

private:
RuntimeScheduler runtimeScheduler_;
};

} // namespace facebook::react
20 changes: 20 additions & 0 deletions ReactCommon/react/renderer/runtimescheduler/SchedulerPriority.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

#pragma once

#include <react/debug/react_native_assert.h>

namespace facebook::react {

enum class SchedulerPriority : int {
Expand All @@ -23,4 +25,22 @@ static constexpr std::underlying_type<SchedulerPriority>::type serialize(
schedulerPriority);
}

static inline SchedulerPriority fromRawValue(double value) {
switch ((int)value) {
case 1:
return SchedulerPriority::ImmediatePriority;
case 2:
return SchedulerPriority::UserBlockingPriority;
case 3:
return SchedulerPriority::NormalPriority;
case 4:
return SchedulerPriority::LowPriority;
case 5:
return SchedulerPriority::IdlePriority;
default:
react_native_assert(false && "Unsupported SchedulerPriority value");
return SchedulerPriority::NormalPriority;
}
}

} // namespace facebook::react
23 changes: 23 additions & 0 deletions ReactCommon/react/renderer/runtimescheduler/Task.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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"

namespace facebook::react {

Task::Task(SchedulerPriority priority, jsi::Function callback)
: priority_(priority), callback_(std::move(callback)) {}

SchedulerPriority Task::getPriority() const {
return priority_;
}

void Task::operator()(jsi::Runtime &runtime) const {
callback_.call(runtime, {});
}

} // namespace facebook::react
36 changes: 36 additions & 0 deletions ReactCommon/react/renderer/runtimescheduler/Task.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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.
*/

#pragma once

#include <jsi/jsi.h>
#include <react/renderer/runtimescheduler/SchedulerPriority.h>

namespace facebook::react {

class Task final {
public:
Task(SchedulerPriority priority, jsi::Function callback);

SchedulerPriority priority_;
jsi::Function callback_;

SchedulerPriority getPriority() const;

void operator()(jsi::Runtime &runtime) const;
};

class TaskPriorityComparer {
public:
inline bool operator()(
std::shared_ptr<Task> const &lhs,
std::shared_ptr<Task> const &rhs) {
return lhs->getPriority() > rhs->getPriority();
}
};

} // namespace facebook::react
3 changes: 2 additions & 1 deletion ReactCommon/react/renderer/scheduler/Scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ Scheduler::Scheduler(
auto uiManagerBinding = UIManagerBinding::createAndInstallIfNeeded(runtime);
uiManagerBinding->attach(uiManager);
if (enableRuntimeScheduler) {
RuntimeSchedulerBinding::createAndInstallIfNeeded(runtime);
RuntimeSchedulerBinding::createAndInstallIfNeeded(
runtime, runtimeExecutor_);
}
});

Expand Down

0 comments on commit 2779129

Please sign in to comment.