-
Notifications
You must be signed in to change notification settings - Fork 6k
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
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Is this actually true? Couldn't multiple task runners share a thread? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
// | ||
// 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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
|
@@ -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 | ||
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Informs There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
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_ |
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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. target_time values are based on the clock used by There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
There was a problem hiding this comment.
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/
There was a problem hiding this comment.
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.