Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow embedders to specify their own task runner interfaces. #8273

Merged
merged 5 commits into from
Mar 27, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -675,12 +675,17 @@ FILE: ../../../flutter/shell/platform/embedder/embedder_engine.h
FILE: ../../../flutter/shell/platform/embedder/embedder_external_texture_gl.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_external_texture_gl.h
FILE: ../../../flutter/shell/platform/embedder/embedder_include.c
FILE: ../../../flutter/shell/platform/embedder/embedder_safe_access.h
FILE: ../../../flutter/shell/platform/embedder/embedder_surface.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_surface.h
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_gl.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_gl.h
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_software.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_software.h
FILE: ../../../flutter/shell/platform/embedder/embedder_task_runner.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_task_runner.h
FILE: ../../../flutter/shell/platform/embedder/embedder_thread_host.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_thread_host.h
FILE: ../../../flutter/shell/platform/embedder/fixtures/a11y_main.dart
FILE: ../../../flutter/shell/platform/embedder/fixtures/simple_main.dart
FILE: ../../../flutter/shell/platform/embedder/platform_view_embedder.cc
Expand Down
4 changes: 2 additions & 2 deletions fml/task_runner.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ class MessageLoopImpl;

class TaskRunner : public fml::RefCountedThreadSafe<TaskRunner> {
public:
virtual ~TaskRunner();

virtual void PostTask(fml::closure task);

virtual void PostTaskForTime(fml::closure task, fml::TimePoint target_time);
Expand All @@ -25,8 +27,6 @@ class TaskRunner : public fml::RefCountedThreadSafe<TaskRunner> {

virtual bool RunsTasksOnCurrentThread();

virtual ~TaskRunner();

static void RunNowOrPostTask(fml::RefPtr<fml::TaskRunner> runner,
fml::closure task);

Expand Down
5 changes: 5 additions & 0 deletions shell/platform/embedder/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,17 @@ source_set("embedder") {
"embedder_external_texture_gl.cc",
"embedder_external_texture_gl.h",
"embedder_include.c",
"embedder_safe_access.h",
"embedder_surface.cc",
"embedder_surface.h",
"embedder_surface_gl.cc",
"embedder_surface_gl.h",
"embedder_surface_software.cc",
"embedder_surface_software.h",
"embedder_task_runner.cc",
"embedder_task_runner.h",
"embedder_thread_host.cc",
"embedder_thread_host.h",
"platform_view_embedder.cc",
"platform_view_embedder.h",
"vsync_waiter_embedder.cc",
Expand Down
59 changes: 31 additions & 28 deletions shell/platform/embedder/embedder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ extern const intptr_t kPlatformStrongDillSize;
#endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
}

#include "flutter/shell/platform/embedder/embedder.h"

#include <type_traits>

#include "flutter/assets/directory_asset_bundle.h"
#include "flutter/common/task_runners.h"
#include "flutter/fml/command_line.h"
Expand All @@ -38,18 +34,11 @@ extern const intptr_t kPlatformStrongDillSize;
#include "flutter/shell/common/switches.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/embedder/embedder_engine.h"
#include "flutter/shell/platform/embedder/embedder_safe_access.h"
#include "flutter/shell/platform/embedder/embedder_task_runner.h"
#include "flutter/shell/platform/embedder/embedder_thread_host.h"
#include "flutter/shell/platform/embedder/platform_view_embedder.h"

#define SAFE_ACCESS(pointer, member, default_value) \
([=]() { \
if (offsetof(std::remove_pointer<decltype(pointer)>::type, member) + \
sizeof(pointer->member) <= \
pointer->struct_size) { \
return pointer->member; \
} \
return static_cast<decltype(pointer->member)>((default_value)); \
})()

static FlutterEngineResult LogEmbedderError(FlutterEngineResult code,
const char* name,
const char* function,
Expand Down Expand Up @@ -408,20 +397,6 @@ FlutterEngineResult FlutterEngineRun(size_t version,
};
}

// Create a thread host with the current thread as the platform thread and all
// other threads managed.
shell::ThreadHost thread_host("io.flutter", shell::ThreadHost::Type::GPU |
shell::ThreadHost::Type::IO |
shell::ThreadHost::Type::UI);
fml::MessageLoop::EnsureInitializedForCurrentThread();
blink::TaskRunners task_runners(
"io.flutter",
fml::MessageLoop::GetCurrent().GetTaskRunner(), // platform
thread_host.gpu_thread->GetTaskRunner(), // gpu
thread_host.ui_thread->GetTaskRunner(), // ui
thread_host.io_thread->GetTaskRunner() // io
);

shell::PlatformViewEmbedder::UpdateSemanticsNodesCallback
update_semantics_nodes_callback = nullptr;
if (SAFE_ACCESS(args, update_semantics_node_callback, nullptr) != nullptr) {
Expand Down Expand Up @@ -602,6 +577,23 @@ FlutterEngineResult FlutterEngineRun(size_t version,
}
}

auto thread_host =
shell::EmbedderThreadHost::CreateEmbedderOrEngineManagedThreadHost(
SAFE_ACCESS(args, custom_task_runners, nullptr));

if (!thread_host || !thread_host->IsValid()) {
FML_LOG(ERROR) << "Could not setup or infer thread configuration to run "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: s/setup/set up/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in followup CL since this has landed.

"the Flutter engine on.";
return LOG_EMBEDDER_ERROR(kInvalidArguments);
}

auto task_runners = thread_host->GetTaskRunners();

if (!task_runners.IsValid()) {
FML_LOG(ERROR) << "Task runner configuration specified is invalid.";
return LOG_EMBEDDER_ERROR(kInvalidArguments);
}

// Step 1: Create the engine.
auto embedder_engine =
std::make_unique<shell::EmbedderEngine>(std::move(thread_host), //
Expand Down Expand Up @@ -940,3 +932,14 @@ FlutterEngineResult FlutterEnginePostRenderThreadTask(FlutterEngine engine,
? kSuccess
: LOG_EMBEDDER_ERROR(kInternalInconsistency);
}

FlutterEngineResult FlutterEngineRunTask(FlutterEngine engine,
const FlutterTask* task) {
if (engine == nullptr) {
return LOG_EMBEDDER_ERROR(kInvalidArguments);
}

return reinterpret_cast<shell::EmbedderEngine*>(engine)->RunTask(task)
? kSuccess
: LOG_EMBEDDER_ERROR(kInvalidArguments);
}
56 changes: 56 additions & 0 deletions shell/platform/embedder/embedder.h
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,49 @@ typedef void (*FlutterUpdateSemanticsCustomActionCallback)(
const FlutterSemanticsCustomAction* /* semantics custom action */,
void* /* user data */);

typedef struct _FlutterTaskRunner* FlutterTaskRunner;

typedef struct {
FlutterTaskRunner runner;
uint64_t task;
} FlutterTask;

typedef void (*FlutterTaskRunnerPostTaskCallback)(
FlutterTask /* task */,
uint64_t /* target time nanos */,
void* /* user data */);

// An interface used by the Flutter engine to execute tasks at the target time
// on a specified thread. There should be a 1-1 relationship between a thread
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a 1-1 relationship

Is this actually true? Couldn't multiple task runners share a thread?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not all thread configurations are known to be stable. This is an artificial restriction that we want to apply to embedder implementations for now. Once we verify that all thread configurations are stable, we can lift this restriction.

// and a task runner. It is undefined behavior to run a task on a thread that is
// not associated with its task runner.
typedef struct {
// The size of this struct. Must be sizeof(FlutterTaskRunnerDescription).
size_t struct_size;
void* user_data;
// May be called from any thread. Should return true if tasks posted on the
// calling thread will be run on that same thread.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a hard time understanding how to reconcile this with the comment saying that running tasks on any thread other than the task runner's thread is undefined behavior. If the intent is that this can be used to check whether the thread it's called on is the task runner's thread, what about calling it something like is_task_runner_thread_callback?

//
// This field is required.
BoolCallback runs_task_on_current_thread_callback;
// May be called from any thread. The given task should be executed by the
// embedder on the thread associated with that task runner by calling
// FlutterEngineRunTask at the given target time. The system monotonic clock
// should be used for the target time. The target time is the absolute time at
// which the task must be returned back to the engine on the correct thread.
//
// This field is required.
FlutterTaskRunnerPostTaskCallback post_task_callback;
} FlutterTaskRunnerDescription;

typedef struct {
// The size of this struct. Must be sizeof(FlutterCustomTaskRunners).
size_t struct_size;
// Sepcify the task runner for the thread on which the |FluterEngineRun| call
chinmaygarde marked this conversation as resolved.
Show resolved Hide resolved
// is made.
const FlutterTaskRunnerDescription* platform_task_runner;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be given a less generic name, if other thread/runners may be added here in the future?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is fairly specific to the Flutter engine and mentioned in the Wiki and other documentation.

} FlutterCustomTaskRunners;

typedef struct {
// The size of this struct. Must be sizeof(FlutterProjectArgs).
size_t struct_size;
Expand Down Expand Up @@ -572,6 +615,11 @@ typedef struct {
// away. Usually, this is done using the `@pragma('vm:entry-point')`
// decoration.
const char* custom_dart_entrypoint;

// Typically the Flutter engine create and manages its internal threads. This
// optional argument allows for the specification of task runner interfaces to
// event loops managed by the embedder on threads it creates.
const FlutterCustomTaskRunners* custom_task_runners;
} FlutterProjectArgs;

FLUTTER_EXPORT
Expand Down Expand Up @@ -715,6 +763,14 @@ FlutterEngineResult FlutterEnginePostRenderThreadTask(FlutterEngine engine,
VoidCallback callback,
void* callback_data);

// Inform the engine to run the specified task. This task has been given to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Informs

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

// the engine via the |FlutterTaskRunnerDescription.post_task_callback|. This
// call must only be made at the target time specified in that callback. Running
// the task before that time is undefined behavior.
FLUTTER_EXPORT
FlutterEngineResult FlutterEngineRunTask(FlutterEngine engine,
const FlutterTask* task);

#if defined(__cplusplus)
} // extern "C"
#endif
Expand Down
16 changes: 14 additions & 2 deletions shell/platform/embedder/embedder_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
namespace shell {

EmbedderEngine::EmbedderEngine(
ThreadHost thread_host,
std::unique_ptr<EmbedderThreadHost> thread_host,
blink::TaskRunners task_runners,
blink::Settings settings,
Shell::CreateCallback<PlatformView> on_create_platform_view,
Expand All @@ -23,7 +23,11 @@ EmbedderEngine::EmbedderEngine(
on_create_platform_view,
on_create_rasterizer)),
external_texture_callback_(external_texture_callback) {
is_valid_ = shell_ != nullptr;
if (!shell_) {
return;
}

is_valid_ = true;
}

EmbedderEngine::~EmbedderEngine() = default;
Expand Down Expand Up @@ -212,4 +216,12 @@ bool EmbedderEngine::PostRenderThreadTask(fml::closure task) {
return true;
}

bool EmbedderEngine::RunTask(const FlutterTask* task) {
if (!IsValid() || task == nullptr) {
return false;
}
return thread_host_->PostTask(reinterpret_cast<int64_t>(task->runner),
task->task);
}

} // namespace shell
8 changes: 6 additions & 2 deletions shell/platform/embedder/embedder_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,23 @@
#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_ENGINE_H_

#include <memory>
#include <unordered_map>

#include "flutter/fml/macros.h"
#include "flutter/shell/common/shell.h"
#include "flutter/shell/common/thread_host.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/embedder/embedder_engine.h"
#include "flutter/shell/platform/embedder/embedder_external_texture_gl.h"
#include "flutter/shell/platform/embedder/embedder_thread_host.h"

namespace shell {

// The object that is returned to the embedder as an opaque pointer to the
// instance of the Flutter engine.
class EmbedderEngine {
public:
EmbedderEngine(ThreadHost thread_host,
EmbedderEngine(std::unique_ptr<EmbedderThreadHost> thread_host,
blink::TaskRunners task_runners,
blink::Settings settings,
Shell::CreateCallback<PlatformView> on_create_platform_view,
Expand Down Expand Up @@ -65,8 +67,10 @@ class EmbedderEngine {

bool PostRenderThreadTask(fml::closure task);

bool RunTask(const FlutterTask* task);

private:
const ThreadHost thread_host_;
const std::unique_ptr<EmbedderThreadHost> thread_host_;
std::unique_ptr<Shell> shell_;
const EmbedderExternalTextureGL::ExternalTextureCallback
external_texture_callback_;
Expand Down
20 changes: 20 additions & 0 deletions shell/platform/embedder/embedder_safe_access.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_SAFE_ACCESS_H_
#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_SAFE_ACCESS_H_

#include <type_traits>

#define SAFE_ACCESS(pointer, member, default_value) \
([=]() { \
if (offsetof(std::remove_pointer<decltype(pointer)>::type, member) + \
sizeof(pointer->member) <= \
pointer->struct_size) { \
return pointer->member; \
} \
return static_cast<decltype(pointer->member)>((default_value)); \
})()

#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_SAFE_ACCESS_H_
72 changes: 72 additions & 0 deletions shell/platform/embedder/embedder_task_runner.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/shell/platform/embedder/embedder_task_runner.h"

#include "flutter/fml/message_loop_impl.h"

namespace shell {

EmbedderTaskRunner::EmbedderTaskRunner(DispatchTable table)
: TaskRunner(nullptr /* loop implemenation*/),
dispatch_table_(std::move(table)) {
FML_DCHECK(dispatch_table_.post_task_callback);
FML_DCHECK(dispatch_table_.runs_task_on_current_thread_callback);
}

EmbedderTaskRunner::~EmbedderTaskRunner() = default;

void EmbedderTaskRunner::PostTask(fml::closure task) {
PostTaskForTime(task, fml::TimePoint::Now());
}

void EmbedderTaskRunner::PostTaskForTime(fml::closure task,
fml::TimePoint target_time) {
if (!task) {
return;
}

uint64_t baton = 0;

{
// Release the lock before the jump via the dispatch table.
std::lock_guard<std::mutex> lock(tasks_mutex_);
baton = ++last_baton_;
pending_tasks_[baton] = task;
}

dispatch_table_.post_task_callback(this, baton, target_time);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

target_time values are based on the clock used by fml::TimePoint::Now(). The embedder will need to expose an API that returns the value of that clock.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added FlutterEngineGetCurrentTime

}

void EmbedderTaskRunner::PostDelayedTask(fml::closure task,
fml::TimeDelta delay) {
PostTaskForTime(task, fml::TimePoint::Now() + delay);
}

bool EmbedderTaskRunner::RunsTasksOnCurrentThread() {
return dispatch_table_.runs_task_on_current_thread_callback();
}

bool EmbedderTaskRunner::PostTask(uint64_t baton) {
fml::closure task;

{
std::lock_guard<std::mutex> lock(tasks_mutex_);
auto found = pending_tasks_.find(baton);
if (found == pending_tasks_.end()) {
FML_LOG(ERROR) << "Embedder attempted to post an unknown task.";
return false;
}
task = found->second;
pending_tasks_.erase(found);

// Let go of the tasks mutex befor executing the task.
}

FML_DCHECK(task);
task();
return true;
}

} // namespace shell
Loading