From a37eb4c6d6d05c8c44fd08b0f37c466b45721051 Mon Sep 17 00:00:00 2001 From: George Wright Date: Wed, 22 Jan 2020 20:35:41 -0800 Subject: [PATCH] Revert "Migrate flutter_runner from flutter_runner::{Thread,Loop} to fml::{Thread,MessageLoop} (#15118)" (#15903) This reverts commit a50f1ef56a05999bfa97a777cca14fd7a00e8454. --- ci/licenses_golden/licenses_flutter | 8 ++ fml/thread.cc | 4 - shell/platform/fuchsia/flutter/BUILD.gn | 8 ++ shell/platform/fuchsia/flutter/component.cc | 25 +++-- shell/platform/fuchsia/flutter/component.h | 4 +- shell/platform/fuchsia/flutter/engine.cc | 32 +++--- shell/platform/fuchsia/flutter/engine.h | 4 +- .../fuchsia/flutter/engine_flutter_runner.gni | 8 ++ .../platform/fuchsia/flutter/fuchsia_intl.cc | 1 + shell/platform/fuchsia/flutter/loop.cc | 47 ++++++++ shell/platform/fuchsia/flutter/loop.h | 17 +++ shell/platform/fuchsia/flutter/main.cc | 14 +-- shell/platform/fuchsia/flutter/runner.cc | 48 ++++---- shell/platform/fuchsia/flutter/runner.h | 5 +- .../fuchsia/flutter/task_observers.cc | 30 +++++ .../platform/fuchsia/flutter/task_observers.h | 21 ++++ .../fuchsia/flutter/task_runner_adapter.cc | 56 ++++++++++ .../fuchsia/flutter/task_runner_adapter.h | 16 +++ shell/platform/fuchsia/flutter/thread.cc | 103 ++++++++++++++++++ shell/platform/fuchsia/flutter/thread.h | 45 ++++++++ .../fuchsia/flutter/vsync_waiter_unittests.cc | 27 +++-- 21 files changed, 448 insertions(+), 75 deletions(-) create mode 100644 shell/platform/fuchsia/flutter/loop.cc create mode 100644 shell/platform/fuchsia/flutter/loop.h create mode 100644 shell/platform/fuchsia/flutter/task_observers.cc create mode 100644 shell/platform/fuchsia/flutter/task_observers.h create mode 100644 shell/platform/fuchsia/flutter/task_runner_adapter.cc create mode 100644 shell/platform/fuchsia/flutter/task_runner_adapter.h create mode 100644 shell/platform/fuchsia/flutter/thread.cc create mode 100644 shell/platform/fuchsia/flutter/thread.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index b6d7374267808..b8930211ebfab 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1020,6 +1020,8 @@ FILE: ../../../flutter/shell/platform/fuchsia/flutter/kernel/extract_far.dart FILE: ../../../flutter/shell/platform/fuchsia/flutter/kernel/framework_shim.dart FILE: ../../../flutter/shell/platform/fuchsia/flutter/kernel/libraries.json FILE: ../../../flutter/shell/platform/fuchsia/flutter/logging.h +FILE: ../../../flutter/shell/platform/fuchsia/flutter/loop.cc +FILE: ../../../flutter/shell/platform/fuchsia/flutter/loop.h FILE: ../../../flutter/shell/platform/fuchsia/flutter/main.cc FILE: ../../../flutter/shell/platform/fuchsia/flutter/meta/aot_product_runtime FILE: ../../../flutter/shell/platform/fuchsia/flutter/meta/aot_runtime @@ -1042,6 +1044,12 @@ FILE: ../../../flutter/shell/platform/fuchsia/flutter/session_connection.cc FILE: ../../../flutter/shell/platform/fuchsia/flutter/session_connection.h FILE: ../../../flutter/shell/platform/fuchsia/flutter/surface.cc FILE: ../../../flutter/shell/platform/fuchsia/flutter/surface.h +FILE: ../../../flutter/shell/platform/fuchsia/flutter/task_observers.cc +FILE: ../../../flutter/shell/platform/fuchsia/flutter/task_observers.h +FILE: ../../../flutter/shell/platform/fuchsia/flutter/task_runner_adapter.cc +FILE: ../../../flutter/shell/platform/fuchsia/flutter/task_runner_adapter.h +FILE: ../../../flutter/shell/platform/fuchsia/flutter/thread.cc +FILE: ../../../flutter/shell/platform/fuchsia/flutter/thread.h FILE: ../../../flutter/shell/platform/fuchsia/flutter/unique_fdio_ns.h FILE: ../../../flutter/shell/platform/fuchsia/flutter/vsync_recorder.cc FILE: ../../../flutter/shell/platform/fuchsia/flutter/vsync_recorder.h diff --git a/fml/thread.cc b/fml/thread.cc index 4f96fd7e08e9d..b6a4802b48728 100644 --- a/fml/thread.cc +++ b/fml/thread.cc @@ -10,8 +10,6 @@ #if defined(OS_WIN) #include -#elif defined(OS_FUCHSIA) -#include #else #include #endif @@ -87,8 +85,6 @@ void Thread::SetCurrentThreadName(const std::string& name) { reinterpret_cast(&info)); } __except (EXCEPTION_CONTINUE_EXECUTION) { } -#elif OS_FUCHSIA - zx::thread::self()->set_property(ZX_PROP_NAME, name.c_str(), name.size()); #else FML_DLOG(INFO) << "Could not set the thread name to '" << name << "' on this platform."; diff --git a/shell/platform/fuchsia/flutter/BUILD.gn b/shell/platform/fuchsia/flutter/BUILD.gn index 6e0b391d3815e..956ccc8a953f7 100644 --- a/shell/platform/fuchsia/flutter/BUILD.gn +++ b/shell/platform/fuchsia/flutter/BUILD.gn @@ -303,6 +303,8 @@ executable("flutter_runner_unittests") { "fuchsia_intl.h", "fuchsia_intl_unittest.cc", "logging.h", + "loop.cc", + "loop.h", "platform_view.cc", "platform_view.h", "platform_view_unittest.cc", @@ -311,6 +313,12 @@ executable("flutter_runner_unittests") { "runner_unittest.cc", "surface.cc", "surface.h", + "task_observers.cc", + "task_observers.h", + "task_runner_adapter.cc", + "task_runner_adapter.h", + "thread.cc", + "thread.h", "vsync_recorder.cc", "vsync_recorder.h", "vsync_waiter.cc", diff --git a/shell/platform/fuchsia/flutter/component.cc b/shell/platform/fuchsia/flutter/component.cc index dee414d344538..9185914e531e6 100644 --- a/shell/platform/fuchsia/flutter/component.cc +++ b/shell/platform/fuchsia/flutter/component.cc @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#define FML_USED_ON_EMBEDDER - #include "component.h" #include @@ -38,6 +36,10 @@ #include "runtime/dart/utils/tempfs.h" #include "runtime/dart/utils/vmo.h" +#include "task_observers.h" +#include "task_runner_adapter.h" +#include "thread.h" + // TODO(kaushikiska): Use these constants from ::llcpp::fuchsia::io // Can read from target object. constexpr uint32_t OPEN_RIGHT_READABLE = 1u; @@ -57,11 +59,11 @@ ActiveApplication Application::Create( fuchsia::sys::StartupInfo startup_info, std::shared_ptr runner_incoming_services, fidl::InterfaceRequest controller) { - std::unique_ptr thread = std::make_unique(); + std::unique_ptr thread = std::make_unique(); std::unique_ptr application; fml::AutoResetWaitableEvent latch; - fml::TaskRunner::RunNowOrPostTask(thread->GetTaskRunner(), [&]() mutable { + async::PostTask(thread->dispatcher(), [&]() mutable { application.reset( new Application(std::move(termination_callback), std::move(package), std::move(startup_info), runner_incoming_services, @@ -345,12 +347,12 @@ Application::Application( settings_.disable_dart_asserts = true; #endif - settings_.task_observer_add = [](intptr_t key, fml::closure callback) { - fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback)); - }; - settings_.task_observer_remove = [](intptr_t key) { - fml::MessageLoop::GetCurrent().RemoveTaskObserver(key); - }; + settings_.task_observer_add = + std::bind(&CurrentMessageLoopAddAfterTaskObserver, std::placeholders::_1, + std::placeholders::_2); + + settings_.task_observer_remove = std::bind( + &CurrentMessageLoopRemoveAfterTaskObserver, std::placeholders::_1); // TODO(FL-117): Re-enable causal async stack traces when this issue is // addressed. @@ -377,7 +379,8 @@ Application::Application( #endif // defined(__aarch64__) auto weak_application = weak_factory_.GetWeakPtr(); - auto platform_task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); + auto platform_task_runner = + CreateFMLTaskRunner(async_get_default_dispatcher()); const std::string component_url = package.resolved_url; settings_.unhandled_exception_callback = [weak_application, platform_task_runner, diff --git a/shell/platform/fuchsia/flutter/component.h b/shell/platform/fuchsia/flutter/component.h index 4843463496127..b852d3dd6bcd2 100644 --- a/shell/platform/fuchsia/flutter/component.h +++ b/shell/platform/fuchsia/flutter/component.h @@ -24,8 +24,8 @@ #include "engine.h" #include "flutter/common/settings.h" #include "flutter/fml/macros.h" -#include "flutter/fml/thread.h" +#include "thread.h" #include "unique_fdio_ns.h" namespace flutter_runner { @@ -33,7 +33,7 @@ namespace flutter_runner { class Application; struct ActiveApplication { - std::unique_ptr thread; + std::unique_ptr thread; std::unique_ptr application; ActiveApplication& operator=(ActiveApplication&& other) noexcept { diff --git a/shell/platform/fuchsia/flutter/engine.cc b/shell/platform/fuchsia/flutter/engine.cc index 484d5b8145cd3..4d8277ba5d27e 100644 --- a/shell/platform/fuchsia/flutter/engine.cc +++ b/shell/platform/fuchsia/flutter/engine.cc @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#define FML_USED_ON_EMBEDDER - #include "engine.h" #include @@ -20,7 +18,9 @@ #include "fuchsia_intl.h" #include "platform_view.h" #include "runtime/dart/utils/files.h" +#include "task_runner_adapter.h" #include "third_party/skia/include/ports/SkFontMgr_fuchsia.h" +#include "thread.h" namespace flutter_runner { @@ -60,10 +60,6 @@ Engine::Engine(Delegate& delegate, fidl::InterfaceRequest directory_request) : delegate_(delegate), thread_label_(std::move(thread_label)), - thread_host_(thread_label_ + ".", - flutter::ThreadHost::Type::IO | - flutter::ThreadHost::Type::UI | - flutter::ThreadHost::Type::GPU), settings_(std::move(settings)), weak_factory_(this) { if (zx::event::create(0, &vsync_event_) != ZX_OK) { @@ -71,6 +67,12 @@ Engine::Engine(Delegate& delegate, return; } + // Launch the threads that will be used to run the shell. These threads will + // be joined in the destructor. + for (auto& thread : threads_) { + thread.reset(new Thread()); + } + // Set up the session connection. auto scenic = svc->Connect(); fidl::InterfaceHandle session; @@ -165,14 +167,12 @@ Engine::Engine(Delegate& delegate, // Get the task runners from the managed threads. The current thread will be // used as the "platform" thread. - fml::MessageLoop::EnsureInitializedForCurrentThread(); - const flutter::TaskRunners task_runners( - thread_label_, // Dart thread labels - fml::MessageLoop::GetCurrent().GetTaskRunner(), // platform - thread_host_.gpu_thread->GetTaskRunner(), // gpu - thread_host_.ui_thread->GetTaskRunner(), // ui - thread_host_.io_thread->GetTaskRunner() // io + thread_label_, // Dart thread labels + CreateFMLTaskRunner(async_get_default_dispatcher()), // platform + CreateFMLTaskRunner(threads_[0]->dispatcher()), // gpu + CreateFMLTaskRunner(threads_[1]->dispatcher()), // ui + CreateFMLTaskRunner(threads_[2]->dispatcher()) // io ); // Setup the callback that will instantiate the rasterizer. @@ -353,6 +353,12 @@ Engine::Engine(Delegate& delegate, Engine::~Engine() { shell_.reset(); + for (const auto& thread : threads_) { + thread->Quit(); + } + for (const auto& thread : threads_) { + thread->Join(); + } } std::pair Engine::GetEngineReturnCode() const { diff --git a/shell/platform/fuchsia/flutter/engine.h b/shell/platform/fuchsia/flutter/engine.h index f1171b5ad3487..6f045e330aa03 100644 --- a/shell/platform/fuchsia/flutter/engine.h +++ b/shell/platform/fuchsia/flutter/engine.h @@ -16,8 +16,8 @@ #include "flutter/fml/macros.h" #include "flutter/shell/common/shell.h" -#include "flutter/shell/common/thread_host.h" #include "isolate_configurator.h" +#include "thread.h" namespace flutter_runner { @@ -53,8 +53,8 @@ class Engine final { private: Delegate& delegate_; const std::string thread_label_; - flutter::ThreadHost thread_host_; flutter::Settings settings_; + std::array, 3> threads_; std::unique_ptr isolate_configurator_; std::unique_ptr shell_; zx::event vsync_event_; diff --git a/shell/platform/fuchsia/flutter/engine_flutter_runner.gni b/shell/platform/fuchsia/flutter/engine_flutter_runner.gni index 3105bded8b50d..59ec0366d6786 100644 --- a/shell/platform/fuchsia/flutter/engine_flutter_runner.gni +++ b/shell/platform/fuchsia/flutter/engine_flutter_runner.gni @@ -55,6 +55,8 @@ template("flutter_runner") { "isolate_configurator.cc", "isolate_configurator.h", "logging.h", + "loop.cc", + "loop.h", "main.cc", "platform_view.cc", "platform_view.h", @@ -64,6 +66,12 @@ template("flutter_runner") { "session_connection.h", "surface.cc", "surface.h", + "task_observers.cc", + "task_observers.h", + "task_runner_adapter.cc", + "task_runner_adapter.h", + "thread.cc", + "thread.h", "unique_fdio_ns.h", "vsync_recorder.cc", "vsync_recorder.h", diff --git a/shell/platform/fuchsia/flutter/fuchsia_intl.cc b/shell/platform/fuchsia/flutter/fuchsia_intl.cc index f6b322befb945..e1f4fa6238ce0 100644 --- a/shell/platform/fuchsia/flutter/fuchsia_intl.cc +++ b/shell/platform/fuchsia/flutter/fuchsia_intl.cc @@ -8,6 +8,7 @@ #include #include +#include "loop.h" #include "rapidjson/document.h" #include "rapidjson/stringbuffer.h" #include "rapidjson/writer.h" diff --git a/shell/platform/fuchsia/flutter/loop.cc b/shell/platform/fuchsia/flutter/loop.cc new file mode 100644 index 0000000000000..6518828c7a96e --- /dev/null +++ b/shell/platform/fuchsia/flutter/loop.cc @@ -0,0 +1,47 @@ +// 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 "loop.h" + +#include +#include + +#include "task_observers.h" + +namespace flutter_runner { + +namespace { + +static void LoopEpilogue(async_loop_t*, void*) { + ExecuteAfterTaskObservers(); +} + +constexpr async_loop_config_t kAttachedLoopConfig = { + .default_accessors = + { + .getter = async_get_default_dispatcher, + .setter = async_set_default_dispatcher, + }, + .make_default_for_current_thread = true, + .epilogue = &LoopEpilogue, +}; + +constexpr async_loop_config_t kDetachedLoopConfig = { + .default_accessors = + { + .getter = async_get_default_dispatcher, + .setter = async_set_default_dispatcher, + }, + .make_default_for_current_thread = false, + .epilogue = &LoopEpilogue, +}; + +} // namespace + +async::Loop* MakeObservableLoop(bool attachToThread) { + return new async::Loop( + &(attachToThread ? kAttachedLoopConfig : kDetachedLoopConfig)); +} + +} // namespace flutter_runner diff --git a/shell/platform/fuchsia/flutter/loop.h b/shell/platform/fuchsia/flutter/loop.h new file mode 100644 index 0000000000000..02339febadf4c --- /dev/null +++ b/shell/platform/fuchsia/flutter/loop.h @@ -0,0 +1,17 @@ +// 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_FUCHSIA_LOOP_H_ +#define FLUTTER_SHELL_PLATFORM_FUCHSIA_LOOP_H_ + +#include + +namespace flutter_runner { + +// Creates a loop which allows task observers to be attached to it. +async::Loop* MakeObservableLoop(bool attachToThread); + +} // namespace flutter_runner + +#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_LOOP_H_ diff --git a/shell/platform/fuchsia/flutter/main.cc b/shell/platform/fuchsia/flutter/main.cc index e8d2b21c8d749..e37a12d275634 100644 --- a/shell/platform/fuchsia/flutter/main.cc +++ b/shell/platform/fuchsia/flutter/main.cc @@ -2,21 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#define FML_USED_ON_EMBEDDER - #include -#include #include #include #include +#include "loop.h" #include "runner.h" #include "runtime/dart/utils/tempfs.h" int main(int argc, char const* argv[]) { - fml::MessageLoop::EnsureInitializedForCurrentThread(); - auto& message_loop = fml::MessageLoop::GetCurrent(); + std::unique_ptr loop(flutter_runner::MakeObservableLoop(true)); std::unique_ptr provider; { @@ -24,8 +21,7 @@ int main(int argc, char const* argv[]) { bool already_started; // Use CreateSynchronously to prevent loss of early events. trace::TraceProviderWithFdio::CreateSynchronously( - async_get_default_dispatcher(), "flutter_runner", &provider, - &already_started); + loop->dispatcher(), "flutter_runner", &provider, &already_started); } // Set up the process-wide /tmp memfs. @@ -33,9 +29,9 @@ int main(int argc, char const* argv[]) { FML_DLOG(INFO) << "Flutter application services initialized."; - flutter_runner::Runner runner(message_loop); + flutter_runner::Runner runner(loop.get()); - message_loop.Run(); + loop->Run(); FML_DLOG(INFO) << "Flutter application services terminated."; diff --git a/shell/platform/fuchsia/flutter/runner.cc b/shell/platform/fuchsia/flutter/runner.cc index 3b4b1b13734c3..2fe0b5626ada6 100644 --- a/shell/platform/fuchsia/flutter/runner.cc +++ b/shell/platform/fuchsia/flutter/runner.cc @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#define FML_USED_ON_EMBEDDER - #include "runner.h" #include @@ -130,6 +128,11 @@ static void SetProcessName() { zx::process::self()->set_property(ZX_PROP_NAME, name.c_str(), name.size()); } +static void SetThreadName(const std::string& thread_name) { + zx::thread::self()->set_property(ZX_PROP_NAME, thread_name.c_str(), + thread_name.size()); +} + #if !defined(DART_PRODUCT) // Register native symbol information for the Dart VM's profiler. static void RegisterProfilerSymbols(const char* symbols_path, @@ -143,8 +146,8 @@ static void RegisterProfilerSymbols(const char* symbols_path, } #endif // !defined(DART_PRODUCT) -Runner::Runner(fml::MessageLoop& message_loop) - : message_loop_(message_loop), context_(sys::ComponentContext::Create()) { +Runner::Runner(async::Loop* loop) + : loop_(loop), context_(sys::ComponentContext::Create()) { #if !defined(DART_PRODUCT) // The VM service isolate uses the process-wide namespace. It writes the // vm service protocol port under /tmp. The VMServiceObject exposes that @@ -162,7 +165,7 @@ Runner::Runner(fml::MessageLoop& message_loop) SetProcessName(); - fml::Thread::SetCurrentThreadName("io.flutter.runner.main"); + SetThreadName("io.flutter.runner.main"); context_->outgoing()->AddPublicService( std::bind(&Runner::RegisterApplication, this, std::placeholders::_1)); @@ -211,13 +214,12 @@ void Runner::StartComponent( // there being multiple application runner instance in the process at the same // time. So it is safe to use the raw pointer. Application::TerminationCallback termination_callback = - [task_runner = message_loop_.GetTaskRunner(), // - application_runner = this // + [task_runner = loop_->dispatcher(), // + application_runner = this // ](const Application* application) { - fml::TaskRunner::RunNowOrPostTask( - task_runner, [application_runner, application]() { - application_runner->OnApplicationTerminate(application); - }); + async::PostTask(task_runner, [application_runner, application]() { + application_runner->OnApplicationTerminate(application); + }); }; auto active_application = Application::Create( @@ -252,11 +254,13 @@ void Runner::OnApplicationTerminate(const Application* application) { active_applications_.erase(application); // Post the task to destroy the application and quit its message loop. - fml::TaskRunner::RunNowOrPostTask( - application_thread->GetTaskRunner(), - fml::MakeCopyable( - [instance = std::move(application_to_destroy), - thread = application_thread.get()]() mutable { instance.reset(); })); + async::PostTask( + application_thread->dispatcher(), + fml::MakeCopyable([instance = std::move(application_to_destroy), + thread = application_thread.get()]() mutable { + instance.reset(); + thread->Quit(); + })); // This works because just posted the quit task on the hosted thread. application_thread->Join(); @@ -283,8 +287,7 @@ bool Runner::SetupTZDataInternal() { #if !defined(DART_PRODUCT) void Runner::SetupTraceObserver() { trace_observer_ = std::make_unique(); - FML_DCHECK(message_loop_.GetTaskRunner()->RunsTasksOnCurrentThread()); - trace_observer_->Start(async_get_default_dispatcher(), [runner = this]() { + trace_observer_->Start(loop_->dispatcher(), [runner = this]() { if (!trace_is_category_enabled("dart:profiler")) { return; } @@ -294,11 +297,10 @@ void Runner::SetupTraceObserver() { } else if (trace_state() == TRACE_STOPPING) { for (auto& it : runner->active_applications_) { fml::AutoResetWaitableEvent latch; - fml::TaskRunner::RunNowOrPostTask( - it.second.thread->GetTaskRunner(), [&]() { - it.second.application->WriteProfileToTrace(); - latch.Signal(); - }); + async::PostTask(it.second.thread->dispatcher(), [&]() { + it.second.application->WriteProfileToTrace(); + latch.Signal(); + }); latch.Wait(); } Dart_StopProfiling(); diff --git a/shell/platform/fuchsia/flutter/runner.h b/shell/platform/fuchsia/flutter/runner.h index fd3f0785da2fa..4abba33a6060f 100644 --- a/shell/platform/fuchsia/flutter/runner.h +++ b/shell/platform/fuchsia/flutter/runner.h @@ -25,12 +25,13 @@ namespace flutter_runner { // their own threads. class Runner final : public fuchsia::sys::Runner { public: - explicit Runner(fml::MessageLoop& message_loop); + explicit Runner(async::Loop* loop); ~Runner(); private: - fml::MessageLoop& message_loop_; + async::Loop* loop_; + std::unique_ptr context_; fidl::BindingSet active_applications_bindings_; std::unordered_map diff --git a/shell/platform/fuchsia/flutter/task_observers.cc b/shell/platform/fuchsia/flutter/task_observers.cc new file mode 100644 index 0000000000000..7a623684ff66e --- /dev/null +++ b/shell/platform/fuchsia/flutter/task_observers.cc @@ -0,0 +1,30 @@ +// 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 "task_observers.h" + +#include + +namespace flutter_runner { + +thread_local std::map tTaskObservers; + +void ExecuteAfterTaskObservers() { + for (const auto& callback : tTaskObservers) { + callback.second(); + } +} + +void CurrentMessageLoopAddAfterTaskObserver(intptr_t key, + fit::closure observer) { + if (observer) { + tTaskObservers[key] = std::move(observer); + } +} + +void CurrentMessageLoopRemoveAfterTaskObserver(intptr_t key) { + tTaskObservers.erase(key); +} + +} // namespace flutter_runner diff --git a/shell/platform/fuchsia/flutter/task_observers.h b/shell/platform/fuchsia/flutter/task_observers.h new file mode 100644 index 0000000000000..5ee27d77e0c5c --- /dev/null +++ b/shell/platform/fuchsia/flutter/task_observers.h @@ -0,0 +1,21 @@ +// 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_FUCHSIA_TASK_OBSERVERS_H_ +#define FLUTTER_SHELL_PLATFORM_FUCHSIA_TASK_OBSERVERS_H_ + +#include + +namespace flutter_runner { + +void ExecuteAfterTaskObservers(); + +void CurrentMessageLoopAddAfterTaskObserver(intptr_t key, + fit::closure observer); + +void CurrentMessageLoopRemoveAfterTaskObserver(intptr_t key); + +} // namespace flutter_runner + +#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_TASK_OBSERVERS_H_ diff --git a/shell/platform/fuchsia/flutter/task_runner_adapter.cc b/shell/platform/fuchsia/flutter/task_runner_adapter.cc new file mode 100644 index 0000000000000..e75cc16e3914e --- /dev/null +++ b/shell/platform/fuchsia/flutter/task_runner_adapter.cc @@ -0,0 +1,56 @@ +// 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 "task_runner_adapter.h" + +#include +#include +#include + +#include "flutter/fml/message_loop_impl.h" + +namespace flutter_runner { + +class CompatTaskRunner : public fml::TaskRunner { + public: + CompatTaskRunner(async_dispatcher_t* dispatcher) + : fml::TaskRunner(nullptr), forwarding_target_(dispatcher) { + FML_DCHECK(forwarding_target_); + } + + void PostTask(const fml::closure& task) override { + async::PostTask(forwarding_target_, task); + } + + void PostTaskForTime(const fml::closure& task, + fml::TimePoint target_time) override { + async::PostTaskForTime( + forwarding_target_, task, + zx::time(target_time.ToEpochDelta().ToNanoseconds())); + } + + void PostDelayedTask(const fml::closure& task, + fml::TimeDelta delay) override { + async::PostDelayedTask(forwarding_target_, task, + zx::duration(delay.ToNanoseconds())); + } + + bool RunsTasksOnCurrentThread() override { + return forwarding_target_ == async_get_default_dispatcher(); + } + + private: + async_dispatcher_t* forwarding_target_; + + FML_DISALLOW_COPY_AND_ASSIGN(CompatTaskRunner); + FML_FRIEND_MAKE_REF_COUNTED(CompatTaskRunner); + FML_FRIEND_REF_COUNTED_THREAD_SAFE(CompatTaskRunner); +}; + +fml::RefPtr CreateFMLTaskRunner( + async_dispatcher_t* dispatcher) { + return fml::MakeRefCounted(dispatcher); +} + +} // namespace flutter_runner diff --git a/shell/platform/fuchsia/flutter/task_runner_adapter.h b/shell/platform/fuchsia/flutter/task_runner_adapter.h new file mode 100644 index 0000000000000..649b2a31e4d6c --- /dev/null +++ b/shell/platform/fuchsia/flutter/task_runner_adapter.h @@ -0,0 +1,16 @@ +// 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. + +#pragma once + +#include + +#include "flutter/fml/task_runner.h" + +namespace flutter_runner { + +fml::RefPtr CreateFMLTaskRunner( + async_dispatcher_t* dispatcher); + +} // namespace flutter_runner diff --git a/shell/platform/fuchsia/flutter/thread.cc b/shell/platform/fuchsia/flutter/thread.cc new file mode 100644 index 0000000000000..f15ea309a239d --- /dev/null +++ b/shell/platform/fuchsia/flutter/thread.cc @@ -0,0 +1,103 @@ +// 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 "thread.h" + +#include +#include + +#include + +#include + +#include "flutter/fml/logging.h" +#include "loop.h" + +namespace flutter_runner { + +typedef void (*ThreadEntry)(Thread*); + +namespace { + +size_t NextPageSizeMultiple(size_t size) { + const size_t page_size = sysconf(_SC_PAGE_SIZE); + FML_CHECK(page_size != 0); + + size = std::max(size, page_size); + + size_t rem = size % page_size; + + if (rem == 0) { + return size; + } + + return size + page_size - rem; +} + +bool CreateThread(pthread_t* thread, + ThreadEntry main, + Thread* argument, + size_t stack_size) { + pthread_attr_t thread_attributes; + + if (pthread_attr_init(&thread_attributes) != 0) { + return false; + } + + stack_size = std::max(NextPageSizeMultiple(PTHREAD_STACK_MIN), + NextPageSizeMultiple(stack_size)); + + if (pthread_attr_setstacksize(&thread_attributes, stack_size) != 0) { + return false; + } + + auto result = + pthread_create(thread, &thread_attributes, + reinterpret_cast(main), argument); + + pthread_attr_destroy(&thread_attributes); + + return result == 0; +} + +} // anonymous namespace + +Thread::Thread() { + loop_.reset(MakeObservableLoop(false)); + valid_ = CreateThread( + &thread_, [](Thread* thread) { thread->Main(); }, this, 1 << 20); +} + +Thread::~Thread() { + Join(); +} + +bool Thread::IsValid() const { + return valid_; +} + +async_dispatcher_t* Thread::dispatcher() const { + return loop_->dispatcher(); +} + +void Thread::Main() { + async_set_default_dispatcher(loop_->dispatcher()); + loop_->Run(); +} + +void Thread::Quit() { + loop_->Quit(); +} + +bool Thread::Join() { + if (!valid_) { + return false; + } + + bool result = pthread_join(thread_, nullptr) == 0; + valid_ = false; + return result; +} + +} // namespace flutter_runner diff --git a/shell/platform/fuchsia/flutter/thread.h b/shell/platform/fuchsia/flutter/thread.h new file mode 100644 index 0000000000000..00d1cef9492dd --- /dev/null +++ b/shell/platform/fuchsia/flutter/thread.h @@ -0,0 +1,45 @@ +// 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_FUCHSIA_THREAD_H_ +#define FLUTTER_SHELL_PLATFORM_FUCHSIA_THREAD_H_ + +#include + +#include + +#include +#include + +#include "flutter/fml/macros.h" + +namespace flutter_runner { + +class Thread { + public: + Thread(); + + ~Thread(); + + void Quit(); + + bool Join(); + + bool IsValid() const; + + async_dispatcher_t* dispatcher() const; + + private: + bool valid_; + pthread_t thread_; + std::unique_ptr loop_; + + void Main(); + + FML_DISALLOW_COPY_AND_ASSIGN(Thread); +}; + +} // namespace flutter_runner + +#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_THREAD_H_ diff --git a/shell/platform/fuchsia/flutter/vsync_waiter_unittests.cc b/shell/platform/fuchsia/flutter/vsync_waiter_unittests.cc index 67bdf3e03f9a7..f1bcfc12ba350 100644 --- a/shell/platform/fuchsia/flutter/vsync_waiter_unittests.cc +++ b/shell/platform/fuchsia/flutter/vsync_waiter_unittests.cc @@ -14,6 +14,8 @@ #include "flutter/fml/time/time_point.h" #include "flutter/shell/common/thread_host.h" #include "flutter/shell/common/vsync_waiter.h" +#include "flutter/shell/platform/fuchsia/flutter/task_runner_adapter.h" +#include "flutter/shell/platform/fuchsia/flutter/thread.h" #include "flutter/shell/platform/fuchsia/flutter/vsync_waiter.h" namespace flutter_runner_test { @@ -48,17 +50,21 @@ class VsyncWaiterTest : public testing::Test { }; TEST_F(VsyncWaiterTest, AwaitVsync) { - flutter::ThreadHost thread_host( - "VsyncWaiterTests.", - flutter::ThreadHost::Type::Platform | flutter::ThreadHost::Type::IO | - flutter::ThreadHost::Type::UI | flutter::ThreadHost::Type::GPU); + std::array, 3> threads; + + for (auto& thread : threads) { + thread.reset(new flutter_runner::Thread()); + } + + async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread); const flutter::TaskRunners task_runners( - "VsyncWaiterTests", // Dart thread labels - thread_host.platform_thread->GetTaskRunner(), // platform - thread_host.gpu_thread->GetTaskRunner(), // gpu - thread_host.ui_thread->GetTaskRunner(), // ui - thread_host.io_thread->GetTaskRunner() // io + "VsyncWaiterTests", // Dart thread labels + flutter_runner::CreateFMLTaskRunner( + async_get_default_dispatcher()), // platform + flutter_runner::CreateFMLTaskRunner(threads[0]->dispatcher()), // gpu + flutter_runner::CreateFMLTaskRunner(threads[1]->dispatcher()), // ui + flutter_runner::CreateFMLTaskRunner(threads[2]->dispatcher()) // io ); auto vsync_waiter = CreateVsyncWaiter(std::move(task_runners)); @@ -76,6 +82,9 @@ TEST_F(VsyncWaiterTest, AwaitVsync) { EXPECT_FALSE(did_timeout); vsync_waiter.reset(); + for (const auto& thread : threads) { + thread->Quit(); + } } TEST_F(VsyncWaiterTest, SnapToNextPhaseOverlapsWithNow) {