From 10ecd9ede1cf492f907134e8d021971589caeb48 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Mon, 3 May 2021 12:59:36 +0200 Subject: [PATCH 01/14] Implement smooth resizing for Linux https://github.com/flutter/flutter/issues/81677 --- ci/licenses_golden/licenses_flutter | 2 + shell/platform/linux/BUILD.gn | 2 + shell/platform/linux/fl_engine.cc | 72 ++------ shell/platform/linux/fl_engine_private.h | 3 + shell/platform/linux/fl_renderer.cc | 66 +++++++- shell/platform/linux/fl_renderer.h | 14 ++ shell/platform/linux/fl_task_runner.cc | 205 +++++++++++++++++++++++ shell/platform/linux/fl_task_runner.h | 75 +++++++++ shell/platform/linux/fl_view.cc | 3 + 9 files changed, 386 insertions(+), 56 deletions(-) create mode 100644 shell/platform/linux/fl_task_runner.cc create mode 100644 shell/platform/linux/fl_task_runner.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index c1eba92abb184..2d4afaff7f585 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1480,6 +1480,8 @@ FILE: ../../../flutter/shell/platform/linux/fl_standard_method_codec.cc FILE: ../../../flutter/shell/platform/linux/fl_standard_method_codec_test.cc FILE: ../../../flutter/shell/platform/linux/fl_string_codec.cc FILE: ../../../flutter/shell/platform/linux/fl_string_codec_test.cc +FILE: ../../../flutter/shell/platform/linux/fl_task_runner.cc +FILE: ../../../flutter/shell/platform/linux/fl_task_runner.h FILE: ../../../flutter/shell/platform/linux/fl_text_input_plugin.cc FILE: ../../../flutter/shell/platform/linux/fl_text_input_plugin.h FILE: ../../../flutter/shell/platform/linux/fl_value.cc diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index 038909683bc18..b7ed3e4946d62 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -114,6 +114,8 @@ source_set("flutter_linux_sources") { "fl_standard_message_codec.cc", "fl_standard_method_codec.cc", "fl_string_codec.cc", + "fl_task_runner.cc", + "fl_task_runner.h", "fl_text_input_plugin.cc", "fl_value.cc", "fl_view.cc", diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 2212b68ed6489..dab088541d848 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -17,8 +17,6 @@ #include "flutter/shell/platform/linux/fl_settings_plugin.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h" -static constexpr int kMicrosecondsPerNanosecond = 1000; - // Unique number associated with platform tasks. static constexpr size_t kPlatformTaskRunnerIdentifier = 1; @@ -32,6 +30,7 @@ struct _FlEngine { FlRenderer* renderer; FlBinaryMessenger* binary_messenger; FlSettingsPlugin* settings_plugin; + FlTaskRunner* task_runner; FlutterEngineAOTData aot_data; FLUTTER_API_SYMBOL(FlutterEngine) engine; FlutterEngineProcTable embedder_api; @@ -143,40 +142,6 @@ static void setup_locales(FlEngine* self) { } } -// Callback to run a Flutter task in the GLib main loop. -static gboolean flutter_source_dispatch(GSource* source, - GSourceFunc callback, - gpointer user_data) { - FlutterSource* fl_source = reinterpret_cast(source); - FlEngine* self = fl_source->engine; - - FlutterEngineResult result = - self->embedder_api.RunTask(self->engine, &fl_source->task); - if (result != kSuccess) { - g_warning("Failed to run Flutter task\n"); - } - - return G_SOURCE_REMOVE; -} - -// Called when the engine is disposed. -static void engine_weak_notify_cb(gpointer user_data, - GObject* where_the_object_was) { - FlutterSource* source = reinterpret_cast(user_data); - source->engine = nullptr; - g_source_destroy(reinterpret_cast(source)); -} - -// Called when a flutter source completes. -static void flutter_source_finalize(GSource* source) { - FlutterSource* fl_source = reinterpret_cast(source); - if (fl_source->engine != nullptr) { - g_object_weak_unref(G_OBJECT(fl_source->engine), engine_weak_notify_cb, - fl_source); - fl_source->engine = nullptr; - } -} - // Called when engine needs a backing store for a specific #FlutterLayer. static bool compositor_create_backing_store_callback( const FlutterBackingStoreConfig* config, @@ -204,16 +169,6 @@ static bool compositor_present_layers_callback(const FlutterLayer** layers, layers_count); } -// Table of functions for Flutter GLib main loop integration. -static GSourceFuncs flutter_source_funcs = { - nullptr, // prepare - nullptr, // check - flutter_source_dispatch, // dispatch - flutter_source_finalize, // finalize - nullptr, - nullptr // Internal usage -}; - // Flutter engine rendering callbacks. static void* fl_engine_gl_proc_resolver(void* user_data, const char* name) { @@ -278,15 +233,7 @@ static void fl_engine_post_task(FlutterTask task, void* user_data) { FlEngine* self = static_cast(user_data); - g_autoptr(GSource) source = - g_source_new(&flutter_source_funcs, sizeof(FlutterSource)); - FlutterSource* fl_source = reinterpret_cast(source); - fl_source->engine = self; - g_object_weak_ref(G_OBJECT(self), engine_weak_notify_cb, fl_source); - fl_source->task = task; - g_source_set_ready_time(source, - target_time_nanos / kMicrosecondsPerNanosecond); - g_source_attach(source, nullptr); + fl_task_runner_post_task(self->task_runner, task, target_time_nanos); } // Called when a platform message is received from the engine. @@ -362,6 +309,9 @@ static void fl_engine_dispose(GObject* object) { g_clear_object(&self->binary_messenger); g_clear_object(&self->settings_plugin); + fl_task_runner_stop(self->task_runner); + g_clear_object(&self->task_runner); + if (self->platform_message_handler_destroy_notify) { self->platform_message_handler_destroy_notify( self->platform_message_handler_data); @@ -407,6 +357,11 @@ G_MODULE_EXPORT FlEngine* fl_engine_new_headless(FlDartProject* project) { return fl_engine_new(project, FL_RENDERER(renderer)); } +static void fl_engine_execute_task(FlutterTask task, gpointer user_data) { + FlEngine* self = FL_ENGINE(user_data); + self->embedder_api.RunTask(self->engine, &task); +} + gboolean fl_engine_start(FlEngine* self, GError** error) { g_return_val_if_fail(FL_IS_ENGINE(self), FALSE); @@ -502,6 +457,8 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { self->settings_plugin = fl_settings_plugin_new(self->binary_messenger); fl_settings_plugin_start(self->settings_plugin); + self->task_runner = fl_task_runner_new(fl_engine_execute_task, self); + result = self->embedder_api.UpdateSemanticsEnabled(self->engine, TRUE); if (result != kSuccess) g_warning("Failed to enable accessibility features on Flutter engine"); @@ -722,3 +679,8 @@ G_MODULE_EXPORT FlBinaryMessenger* fl_engine_get_binary_messenger( g_return_val_if_fail(FL_IS_ENGINE(self), nullptr); return self->binary_messenger; } + +FlTaskRunner* fl_engine_get_task_runner(FlEngine* self) { + g_return_val_if_fail(FL_IS_ENGINE(self), nullptr); + return self->task_runner; +} diff --git a/shell/platform/linux/fl_engine_private.h b/shell/platform/linux/fl_engine_private.h index 23f186921fca6..3884330b406d1 100644 --- a/shell/platform/linux/fl_engine_private.h +++ b/shell/platform/linux/fl_engine_private.h @@ -9,6 +9,7 @@ #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/linux/fl_renderer.h" +#include "flutter/shell/platform/linux/fl_task_runner.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" @@ -226,6 +227,8 @@ GBytes* fl_engine_send_platform_message_finish(FlEngine* engine, GAsyncResult* result, GError** error); +FlTaskRunner* fl_engine_get_task_runner(FlEngine* engine); + G_END_DECLS #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_ENGINE_PRIVATE_H_ diff --git a/shell/platform/linux/fl_renderer.cc b/shell/platform/linux/fl_renderer.cc index 1b3e44399b32a..76cfbfad22d93 100644 --- a/shell/platform/linux/fl_renderer.cc +++ b/shell/platform/linux/fl_renderer.cc @@ -9,19 +9,50 @@ #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/linux/fl_backing_store_provider.h" +#include "flutter/shell/platform/linux/fl_engine_private.h" G_DEFINE_QUARK(fl_renderer_error_quark, fl_renderer_error) typedef struct { FlView* view; + // target dimension for resizing + int target_width; + int target_height; + + // whether the renderer waits for frame render + bool blocking_main_thread; + + // true if frame was completed; resizing is not synchronized until first frame + // was rendered + bool had_first_frame; + GdkGLContext* main_context; GdkGLContext* resource_context; } FlRendererPrivate; G_DEFINE_TYPE_WITH_PRIVATE(FlRenderer, fl_renderer, G_TYPE_OBJECT) -static void fl_renderer_class_init(FlRendererClass* klass) {} +static void fl_renderer_unblock_main_thread(FlRenderer* self) { + FlRendererPrivate* priv = reinterpret_cast( + fl_renderer_get_instance_private(self)); + if (priv->blocking_main_thread) { + priv->blocking_main_thread = false; + + FlTaskRunner* runner = + fl_engine_get_task_runner(fl_view_get_engine(priv->view)); + fl_task_runner_release_main_thread(runner); + } +} + +static void fl_renderer_dispose(GObject* self) { + fl_renderer_unblock_main_thread(FL_RENDERER(self)); + G_OBJECT_CLASS(fl_renderer_parent_class)->dispose(self); +} + +static void fl_renderer_class_init(FlRendererClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_renderer_dispose; +} static void fl_renderer_init(FlRenderer* self) {} @@ -109,9 +140,42 @@ gboolean fl_renderer_collect_backing_store( backing_store); } +void fl_renderer_wait_for_frame(FlRenderer* self, + int target_width, + int target_height) { + FlRendererPrivate* priv = reinterpret_cast( + fl_renderer_get_instance_private(self)); + + priv->target_width = target_width; + priv->target_height = target_height; + + if (priv->had_first_frame && !priv->blocking_main_thread) { + priv->blocking_main_thread = true; + FlTaskRunner* runner = + fl_engine_get_task_runner(fl_view_get_engine(priv->view)); + fl_task_runner_block_main_thread(runner); + } +} + gboolean fl_renderer_present_layers(FlRenderer* self, const FlutterLayer** layers, size_t layers_count) { + FlRendererPrivate* priv = reinterpret_cast( + fl_renderer_get_instance_private(self)); + + // ignore incoming frame with wrong dimensions in trivial case with just one + // layer + if (priv->blocking_main_thread && layers_count == 1 && + layers[0]->offset.x == 0 && layers[0]->offset.y == 0 && + (layers[0]->size.width != priv->target_width || + layers[0]->size.height != priv->target_height)) { + return true; + } + + priv->had_first_frame = true; + + fl_renderer_unblock_main_thread(self); + return FL_RENDERER_GET_CLASS(self)->present_layers(self, layers, layers_count); } diff --git a/shell/platform/linux/fl_renderer.h b/shell/platform/linux/fl_renderer.h index 17cacd4c41480..18480f57ea320 100644 --- a/shell/platform/linux/fl_renderer.h +++ b/shell/platform/linux/fl_renderer.h @@ -242,6 +242,20 @@ gboolean fl_renderer_present_layers(FlRenderer* renderer, const FlutterLayer** layers, size_t layers_count); +/** + * fl_renderer_wait_for_frame + * @renderer: an #FlRenderer. + * @target_width: width of frame being waited for + * @target_height: height of frame being waited for + * + * Holds the thread until frame with requested dimensions is presented. + * While waiting for frame flutter platform and raster tasks are being + * processed. + */ +void fl_renderer_wait_for_frame(FlRenderer* renderer, + int target_width, + int target_height); + G_END_DECLS #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_RENDERER_H_ diff --git a/shell/platform/linux/fl_task_runner.cc b/shell/platform/linux/fl_task_runner.cc new file mode 100644 index 0000000000000..b840df7c9f88c --- /dev/null +++ b/shell/platform/linux/fl_task_runner.cc @@ -0,0 +1,205 @@ +#include "flutter/shell/platform/linux/fl_task_runner.h" + +static constexpr int kMicrosecondsPerNanosecond = 1000; +static constexpr int kMillisecondsPerMicrosecond = 1000; + +struct _FlTaskRunner { + GObject parent_instance; + + FlTaskExecutor executor; + gpointer executor_user_data; + + GMutex mutex; + GCond cond; + + guint timeout_source_id; + GList /**/* pending_tasks; + gboolean blocking_main_thread; + + gboolean stopped; +}; + +typedef struct _FlTaskRunnerTask { + // absolute time of task (based on g_get_monotonic_time) + gint64 task_time_micros; + FlutterTask task; +} FlTaskRunnerTask; + +G_DEFINE_TYPE(FlTaskRunner, fl_task_runner, G_TYPE_OBJECT) + +static void fl_task_runner_dispose(GObject* object); + +static void fl_task_runner_class_init(FlTaskRunnerClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_task_runner_dispose; +} + +static void fl_task_runner_init(FlTaskRunner* self) { + g_mutex_init(&self->mutex); + g_cond_init(&self->cond); +} + +void fl_task_runner_dispose(GObject* object) { + FlTaskRunner* self = FL_TASK_RUNNER(object); + + // this should never happen because the task runner is retained while blocking + // main thread + g_assert(!self->blocking_main_thread); + + g_mutex_clear(&self->mutex); + g_cond_clear(&self->cond); + + g_list_free_full(self->pending_tasks, g_free); + if (self->timeout_source_id != 0) { + g_source_remove(self->timeout_source_id); + } + + G_OBJECT_CLASS(fl_task_runner_parent_class)->dispose(object); +} + +FlTaskRunner* fl_task_runner_new(FlTaskExecutor executor, + gpointer executor_user_data) { + FlTaskRunner* res = + FL_TASK_RUNNER(g_object_new(fl_task_runner_get_type(), nullptr)); + res->executor = executor; + res->executor_user_data = executor_user_data; + return res; +} + +// Removes expired tasks from the task queue and executes them. +// The execution is performed with mutex unlocked. +static void fl_task_runner_process_expired_tasks_locked(FlTaskRunner* self) { + GList* expired_tasks = nullptr; + + gint64 current_time = g_get_monotonic_time(); + + GList* l = self->pending_tasks; + while (l != nullptr) { + FlTaskRunnerTask* task = static_cast(l->data); + if (task->task_time_micros <= current_time) { + GList* link = l; + l = l->next; + self->pending_tasks = g_list_remove_link(self->pending_tasks, link); + expired_tasks = g_list_concat(expired_tasks, link); + } else { + l = l->next; + } + } + + g_mutex_unlock(&self->mutex); + + l = expired_tasks; + while (l != nullptr && !self->stopped) { + FlTaskRunnerTask* task = static_cast(l->data); + self->executor(task->task, self->executor_user_data); + l = l->next; + } + + g_list_free_full(expired_tasks, g_free); + + g_mutex_lock(&self->mutex); +} + +static void fl_task_runner_tasks_did_change_locked(FlTaskRunner* self); + +// Invoked from a timeout source. Removes and executes expired tasks +// and rechedules timeout if needed. +static gboolean fl_task_runner_on_expired_timeout(gpointer data) { + FlTaskRunner* self = FL_TASK_RUNNER(data); + + g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->mutex); + (void)locker; // unused variable + + g_object_ref(self); + + self->timeout_source_id = 0; + fl_task_runner_process_expired_tasks_locked(self); + + // reschedule timeout + fl_task_runner_tasks_did_change_locked(self); + + g_object_unref(self); + + return FALSE; +} + +// Returns the absolute time of next expired task (in microseconds, based on +// g_get_monotonic_time). If no task is scheduled returns G_MAXINT64. +static gint64 fl_task_runner_next_task_expiration_time_locked( + FlTaskRunner* self) { + gint64 min_time = G_MAXINT64; + GList* l = self->pending_tasks; + while (l != nullptr) { + FlTaskRunnerTask* task = static_cast(l->data); + min_time = MIN(min_time, task->task_time_micros); + l = l->next; + } + return min_time; +} + +static void fl_task_runner_tasks_did_change_locked(FlTaskRunner* self) { + if (self->blocking_main_thread) { + // Wake up blocked thread + g_cond_signal(&self->cond); + } else { + // Reschedule timeout + if (self->timeout_source_id != 0) { + g_source_remove(self->timeout_source_id); + self->timeout_source_id = 0; + } + gint64 min_time = fl_task_runner_next_task_expiration_time_locked(self); + if (min_time != G_MAXINT64) { + gint64 remaining = MAX(min_time - g_get_monotonic_time(), 0); + self->timeout_source_id = + g_timeout_add(remaining / kMillisecondsPerMicrosecond + 1, + fl_task_runner_on_expired_timeout, self); + } + } +} + +void fl_task_runner_stop(FlTaskRunner* self) { + // No locking necessary, stop is only set and read on main thread + self->stopped = true; +} + +void fl_task_runner_post_task(FlTaskRunner* self, + FlutterTask task, + uint64_t target_time_nanos) { + g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->mutex); + (void)locker; // unused variable + + FlTaskRunnerTask* runner_task = g_new0(FlTaskRunnerTask, 1); + runner_task->task = task; + runner_task->task_time_micros = + target_time_nanos / kMicrosecondsPerNanosecond; + + self->pending_tasks = g_list_append(self->pending_tasks, runner_task); + fl_task_runner_tasks_did_change_locked(self); +} + +void fl_task_runner_block_main_thread(FlTaskRunner* self) { + g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->mutex); + (void)locker; // unused variable + + g_return_if_fail(self->blocking_main_thread == FALSE); + + g_object_ref(self); + + self->blocking_main_thread = true; + while (self->blocking_main_thread) { + g_cond_wait_until(&self->cond, &self->mutex, + fl_task_runner_next_task_expiration_time_locked(self)); + fl_task_runner_process_expired_tasks_locked(self); + } + + g_object_unref(self); +} + +void fl_task_runner_release_main_thread(FlTaskRunner* self) { + g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->mutex); + (void)locker; // unused variable + + g_return_if_fail(self->blocking_main_thread == TRUE); + + self->blocking_main_thread = FALSE; + g_cond_signal(&self->cond); +} diff --git a/shell/platform/linux/fl_task_runner.h b/shell/platform/linux/fl_task_runner.h new file mode 100644 index 0000000000000..d5ff2d6a3424c --- /dev/null +++ b/shell/platform/linux/fl_task_runner.h @@ -0,0 +1,75 @@ +// Copyright 2021 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_LINUX_FL_TASK_RUNNER_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_TASK_RUNNER_H_ + +#include + +#include "flutter/shell/platform/embedder/embedder.h" + +G_BEGIN_DECLS + +G_DECLARE_FINAL_TYPE(FlTaskRunner, fl_task_runner, FL, TASK_RUNNER, GObject); + +typedef void (*FlTaskExecutor)(FlutterTask task, gpointer user_data); + +/** + * fl_task_runner_new + * @executor: Function responsible for executing fluter tasks. + * @executor_user_data: user data for executor. + * + * Creates new task runner instance. + * + * Returns: an #FlTaskRunner. + */ +FlTaskRunner* fl_task_runner_new(FlTaskExecutor executor, + gpointer executor_user_data); + +/** + * fl_task_runner_post_task + * @task_runner: an #FlTaskRunner. + * @task: flutter task being scheduled + * @target_time_nanos: absolute time in nanoseconds + * + * Posts a flutter task to be executed on main thread. This function is thread + * safe and may be called from any thread. + */ +void fl_task_runner_post_task(FlTaskRunner* task_runner, + FlutterTask task, + uint64_t target_time_nanos); + +/** + * fl_task_runner_stop + * @task_runner: an #FlTaskRunner. + * + * Requests stop. After this method completes no more tasks will be executed + * on the task runner. Remaining scheduled tasks will be invoked. + * Must be invoked on main thread. + */ +void fl_task_runner_stop(FlTaskRunner* task_runner); + +/** + * fl_task_runner_block_main_thread + * @task_runner: an #FlTaskRunner. + * + * Blocks main thread until fl_task_runner_release_main_thread is called. + * While main thread is blocked tasks posted to #FlTaskRunner are executed as + * usual. + * Must be invoked on main thread. + */ +void fl_task_runner_block_main_thread(FlTaskRunner* task_runner); + +/** + * fl_task_runner_release_main_thread + * @task_runner: an #FlTaskRunner. + * + * Unblocks main thread. This will resume normal processing of main loop. + * Can be invoked from any thread. + */ +void fl_task_runner_release_main_thread(FlTaskRunner* self); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_TASK_RUNNER_H_ diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index 4287f60b6c4be..b14d3632a4c44 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -137,6 +137,9 @@ static void fl_view_geometry_changed(FlView* self) { fl_engine_send_window_metrics_event( self->engine, allocation.width * scale_factor, allocation.height * scale_factor, scale_factor); + + fl_renderer_wait_for_frame(self->renderer, allocation.width * scale_factor, + allocation.height * scale_factor); } // Implements FlPluginRegistry::get_registrar_for_plugin. From 1334ea8e2add5ca1f47fc51f57e86f36139a2842 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Mon, 3 May 2021 13:28:30 +0200 Subject: [PATCH 02/14] Fix licenses --- shell/platform/linux/fl_task_runner.cc | 4 ++++ shell/platform/linux/fl_task_runner.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/shell/platform/linux/fl_task_runner.cc b/shell/platform/linux/fl_task_runner.cc index b840df7c9f88c..379fd663d845a 100644 --- a/shell/platform/linux/fl_task_runner.cc +++ b/shell/platform/linux/fl_task_runner.cc @@ -1,3 +1,7 @@ +// 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/linux/fl_task_runner.h" static constexpr int kMicrosecondsPerNanosecond = 1000; diff --git a/shell/platform/linux/fl_task_runner.h b/shell/platform/linux/fl_task_runner.h index d5ff2d6a3424c..e70a0da6d64f0 100644 --- a/shell/platform/linux/fl_task_runner.h +++ b/shell/platform/linux/fl_task_runner.h @@ -1,4 +1,4 @@ -// Copyright 2021 The Flutter Authors. All rights reserved. +// 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. From 481c196fe1127af4559cd4dcd0e8a048da6a3011 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Mon, 3 May 2021 13:37:56 +0200 Subject: [PATCH 03/14] Fix comment --- shell/platform/linux/fl_task_runner.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/linux/fl_task_runner.h b/shell/platform/linux/fl_task_runner.h index e70a0da6d64f0..3c96e1224d5fd 100644 --- a/shell/platform/linux/fl_task_runner.h +++ b/shell/platform/linux/fl_task_runner.h @@ -45,7 +45,7 @@ void fl_task_runner_post_task(FlTaskRunner* task_runner, * @task_runner: an #FlTaskRunner. * * Requests stop. After this method completes no more tasks will be executed - * on the task runner. Remaining scheduled tasks will be invoked. + * by the task runner. Remaining scheduled tasks will be ignored. * Must be invoked on main thread. */ void fl_task_runner_stop(FlTaskRunner* task_runner); From 31f195e2db01b0aaf9acacfa9b519b449f77601e Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Tue, 4 May 2021 16:51:20 +0200 Subject: [PATCH 04/14] Create TaskRunner first --- shell/platform/linux/fl_engine.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index dab088541d848..e6df37a129b6a 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -365,6 +365,8 @@ static void fl_engine_execute_task(FlutterTask task, gpointer user_data) { gboolean fl_engine_start(FlEngine* self, GError** error) { g_return_val_if_fail(FL_IS_ENGINE(self), FALSE); + self->task_runner = fl_task_runner_new(fl_engine_execute_task, self); + FlutterRendererConfig config = {}; config.type = kOpenGL; config.open_gl.struct_size = sizeof(FlutterOpenGLRendererConfig); @@ -457,8 +459,6 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { self->settings_plugin = fl_settings_plugin_new(self->binary_messenger); fl_settings_plugin_start(self->settings_plugin); - self->task_runner = fl_task_runner_new(fl_engine_execute_task, self); - result = self->embedder_api.UpdateSemanticsEnabled(self->engine, TRUE); if (result != kSuccess) g_warning("Failed to enable accessibility features on Flutter engine"); From 06e6531acafc0de5430f7ba2180826afc881b232 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Wed, 5 May 2021 16:45:46 +0200 Subject: [PATCH 05/14] Nits --- shell/platform/linux/fl_renderer.h | 2 +- shell/platform/linux/fl_task_runner.h | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/shell/platform/linux/fl_renderer.h b/shell/platform/linux/fl_renderer.h index 18480f57ea320..5cd56bdb89aea 100644 --- a/shell/platform/linux/fl_renderer.h +++ b/shell/platform/linux/fl_renderer.h @@ -243,7 +243,7 @@ gboolean fl_renderer_present_layers(FlRenderer* renderer, size_t layers_count); /** - * fl_renderer_wait_for_frame + * fl_renderer_wait_for_frame: * @renderer: an #FlRenderer. * @target_width: width of frame being waited for * @target_height: height of frame being waited for diff --git a/shell/platform/linux/fl_task_runner.h b/shell/platform/linux/fl_task_runner.h index 3c96e1224d5fd..43f3617bd2f55 100644 --- a/shell/platform/linux/fl_task_runner.h +++ b/shell/platform/linux/fl_task_runner.h @@ -16,8 +16,8 @@ G_DECLARE_FINAL_TYPE(FlTaskRunner, fl_task_runner, FL, TASK_RUNNER, GObject); typedef void (*FlTaskExecutor)(FlutterTask task, gpointer user_data); /** - * fl_task_runner_new - * @executor: Function responsible for executing fluter tasks. + * fl_task_runner_new: + * @executor: Function responsible for executing Flutter tasks. * @executor_user_data: user data for executor. * * Creates new task runner instance. @@ -28,12 +28,12 @@ FlTaskRunner* fl_task_runner_new(FlTaskExecutor executor, gpointer executor_user_data); /** - * fl_task_runner_post_task + * fl_task_runner_post_task: * @task_runner: an #FlTaskRunner. - * @task: flutter task being scheduled + * @task: Flutter task being scheduled * @target_time_nanos: absolute time in nanoseconds * - * Posts a flutter task to be executed on main thread. This function is thread + * Posts a Flutter task to be executed on main thread. This function is thread * safe and may be called from any thread. */ void fl_task_runner_post_task(FlTaskRunner* task_runner, @@ -41,7 +41,7 @@ void fl_task_runner_post_task(FlTaskRunner* task_runner, uint64_t target_time_nanos); /** - * fl_task_runner_stop + * fl_task_runner_stop: * @task_runner: an #FlTaskRunner. * * Requests stop. After this method completes no more tasks will be executed @@ -51,7 +51,7 @@ void fl_task_runner_post_task(FlTaskRunner* task_runner, void fl_task_runner_stop(FlTaskRunner* task_runner); /** - * fl_task_runner_block_main_thread + * fl_task_runner_block_main_thread: * @task_runner: an #FlTaskRunner. * * Blocks main thread until fl_task_runner_release_main_thread is called. @@ -62,7 +62,7 @@ void fl_task_runner_stop(FlTaskRunner* task_runner); void fl_task_runner_block_main_thread(FlTaskRunner* task_runner); /** - * fl_task_runner_release_main_thread + * fl_task_runner_release_main_thread: * @task_runner: an #FlTaskRunner. * * Unblocks main thread. This will resume normal processing of main loop. From f958f1fe305e6a9efceedbf1b73f24beb3053761 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Wed, 5 May 2021 23:41:33 +0200 Subject: [PATCH 06/14] Missing comment --- shell/platform/linux/fl_engine_private.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/shell/platform/linux/fl_engine_private.h b/shell/platform/linux/fl_engine_private.h index 3884330b406d1..7043ad07f54f3 100644 --- a/shell/platform/linux/fl_engine_private.h +++ b/shell/platform/linux/fl_engine_private.h @@ -227,6 +227,13 @@ GBytes* fl_engine_send_platform_message_finish(FlEngine* engine, GAsyncResult* result, GError** error); +/** + * fl_engine_get_task_runner: + * @engine: an #FlEngine. + * @result: a #FlTaskRunner. + * + * Returns: task runner responsible for scheduling Flutter tasks. + */ FlTaskRunner* fl_engine_get_task_runner(FlEngine* engine); G_END_DECLS From 4e189cbbb08709003e9420b44913b0dd0a92c67c Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Wed, 5 May 2021 23:44:20 +0200 Subject: [PATCH 07/14] FlutterSource is not used anymore --- shell/platform/linux/fl_engine.cc | 7 ------- 1 file changed, 7 deletions(-) diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index e6df37a129b6a..d136dd6ba0823 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -58,13 +58,6 @@ G_DEFINE_TYPE_WITH_CODE( G_IMPLEMENT_INTERFACE(fl_plugin_registry_get_type(), fl_engine_plugin_registry_iface_init)) -// Subclass of GSource that integrates Flutter tasks into the GLib main loop. -typedef struct { - GSource parent; - FlEngine* engine; - FlutterTask task; -} FlutterSource; - // Parse a locale into its components. static void parse_locale(const gchar* locale, gchar** language, From 7f90e63076b40c16b8b0be84f8ffe1973a218e0e Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Wed, 5 May 2021 23:53:11 +0200 Subject: [PATCH 08/14] Remove FlTaskExecutor --- shell/platform/linux/fl_engine.cc | 11 ++++---- shell/platform/linux/fl_engine_private.h | 9 +++++++ shell/platform/linux/fl_task_runner.cc | 34 ++++++++++++++++-------- shell/platform/linux/fl_task_runner.h | 6 ++--- 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index d136dd6ba0823..d4e315a21dd95 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -350,15 +350,10 @@ G_MODULE_EXPORT FlEngine* fl_engine_new_headless(FlDartProject* project) { return fl_engine_new(project, FL_RENDERER(renderer)); } -static void fl_engine_execute_task(FlutterTask task, gpointer user_data) { - FlEngine* self = FL_ENGINE(user_data); - self->embedder_api.RunTask(self->engine, &task); -} - gboolean fl_engine_start(FlEngine* self, GError** error) { g_return_val_if_fail(FL_IS_ENGINE(self), FALSE); - self->task_runner = fl_task_runner_new(fl_engine_execute_task, self); + self->task_runner = fl_task_runner_new(self); FlutterRendererConfig config = {}; config.type = kOpenGL; @@ -677,3 +672,7 @@ FlTaskRunner* fl_engine_get_task_runner(FlEngine* self) { g_return_val_if_fail(FL_IS_ENGINE(self), nullptr); return self->task_runner; } + +void fl_engine_execute_task(FlEngine* self, FlutterTask* task) { + self->embedder_api.RunTask(self->engine, task); +} diff --git a/shell/platform/linux/fl_engine_private.h b/shell/platform/linux/fl_engine_private.h index 7043ad07f54f3..95e6daa19f294 100644 --- a/shell/platform/linux/fl_engine_private.h +++ b/shell/platform/linux/fl_engine_private.h @@ -236,6 +236,15 @@ GBytes* fl_engine_send_platform_message_finish(FlEngine* engine, */ FlTaskRunner* fl_engine_get_task_runner(FlEngine* engine); +/** + * fl_engine_execute_task: + * @engine: an #FlEngine. + * @task: a #FlutterTask to execute. + * + * Executes given Flutter task. + */ +void fl_engine_execute_task(FlEngine* engine, FlutterTask* task); + G_END_DECLS #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_ENGINE_PRIVATE_H_ diff --git a/shell/platform/linux/fl_task_runner.cc b/shell/platform/linux/fl_task_runner.cc index 379fd663d845a..6892479e53299 100644 --- a/shell/platform/linux/fl_task_runner.cc +++ b/shell/platform/linux/fl_task_runner.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "flutter/shell/platform/linux/fl_task_runner.h" +#include "flutter/shell/platform/linux/fl_engine_private.h" static constexpr int kMicrosecondsPerNanosecond = 1000; static constexpr int kMillisecondsPerMicrosecond = 1000; @@ -10,8 +11,7 @@ static constexpr int kMillisecondsPerMicrosecond = 1000; struct _FlTaskRunner { GObject parent_instance; - FlTaskExecutor executor; - gpointer executor_user_data; + FlEngine* engine; GMutex mutex; GCond cond; @@ -42,6 +42,12 @@ static void fl_task_runner_init(FlTaskRunner* self) { g_cond_init(&self->cond); } +static void engine_weak_notify_cb(gpointer user_data, + GObject* where_the_object_was) { + FlTaskRunner* self = FL_TASK_RUNNER(user_data); + self->engine = nullptr; +} + void fl_task_runner_dispose(GObject* object) { FlTaskRunner* self = FL_TASK_RUNNER(object); @@ -49,6 +55,11 @@ void fl_task_runner_dispose(GObject* object) { // main thread g_assert(!self->blocking_main_thread); + if (self->engine != nullptr) { + g_object_weak_unref(G_OBJECT(self->engine), engine_weak_notify_cb, self); + self->engine = nullptr; + } + g_mutex_clear(&self->mutex); g_cond_clear(&self->cond); @@ -60,12 +71,11 @@ void fl_task_runner_dispose(GObject* object) { G_OBJECT_CLASS(fl_task_runner_parent_class)->dispose(object); } -FlTaskRunner* fl_task_runner_new(FlTaskExecutor executor, - gpointer executor_user_data) { +FlTaskRunner* fl_task_runner_new(FlEngine* engine) { FlTaskRunner* res = FL_TASK_RUNNER(g_object_new(fl_task_runner_get_type(), nullptr)); - res->executor = executor; - res->executor_user_data = executor_user_data; + res->engine = engine; + g_object_weak_ref(G_OBJECT(engine), engine_weak_notify_cb, res); return res; } @@ -91,11 +101,13 @@ static void fl_task_runner_process_expired_tasks_locked(FlTaskRunner* self) { g_mutex_unlock(&self->mutex); - l = expired_tasks; - while (l != nullptr && !self->stopped) { - FlTaskRunnerTask* task = static_cast(l->data); - self->executor(task->task, self->executor_user_data); - l = l->next; + if (self->engine) { + l = expired_tasks; + while (l != nullptr && !self->stopped) { + FlTaskRunnerTask* task = static_cast(l->data); + fl_engine_execute_task(self->engine, &task->task); + l = l->next; + } } g_list_free_full(expired_tasks, g_free); diff --git a/shell/platform/linux/fl_task_runner.h b/shell/platform/linux/fl_task_runner.h index 43f3617bd2f55..8538ae7eac6d3 100644 --- a/shell/platform/linux/fl_task_runner.h +++ b/shell/platform/linux/fl_task_runner.h @@ -8,13 +8,12 @@ #include #include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" G_BEGIN_DECLS G_DECLARE_FINAL_TYPE(FlTaskRunner, fl_task_runner, FL, TASK_RUNNER, GObject); -typedef void (*FlTaskExecutor)(FlutterTask task, gpointer user_data); - /** * fl_task_runner_new: * @executor: Function responsible for executing Flutter tasks. @@ -24,8 +23,7 @@ typedef void (*FlTaskExecutor)(FlutterTask task, gpointer user_data); * * Returns: an #FlTaskRunner. */ -FlTaskRunner* fl_task_runner_new(FlTaskExecutor executor, - gpointer executor_user_data); +FlTaskRunner* fl_task_runner_new(FlEngine* engine); /** * fl_task_runner_post_task: From e49cb2f41742b31d73777768c80e529ba83b70cc Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 6 May 2021 00:02:08 +0200 Subject: [PATCH 09/14] Check the argument --- shell/platform/linux/fl_engine.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index d4e315a21dd95..4e8ffa6afb980 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -674,5 +674,6 @@ FlTaskRunner* fl_engine_get_task_runner(FlEngine* self) { } void fl_engine_execute_task(FlEngine* self, FlutterTask* task) { + g_return_if_fail(FL_IS_ENGINE(self)); self->embedder_api.RunTask(self->engine, task); } From 46ef3ca1340924ecdf7750a164f42b0c2a7f7238 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 6 May 2021 01:59:54 +0200 Subject: [PATCH 10/14] Fix comments --- shell/platform/linux/fl_renderer.h | 2 +- shell/platform/linux/fl_task_runner.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/shell/platform/linux/fl_renderer.h b/shell/platform/linux/fl_renderer.h index 5cd56bdb89aea..545f7b8f584d7 100644 --- a/shell/platform/linux/fl_renderer.h +++ b/shell/platform/linux/fl_renderer.h @@ -249,7 +249,7 @@ gboolean fl_renderer_present_layers(FlRenderer* renderer, * @target_height: height of frame being waited for * * Holds the thread until frame with requested dimensions is presented. - * While waiting for frame flutter platform and raster tasks are being + * While waiting for frame Flutter platform and raster tasks are being * processed. */ void fl_renderer_wait_for_frame(FlRenderer* renderer, diff --git a/shell/platform/linux/fl_task_runner.h b/shell/platform/linux/fl_task_runner.h index 8538ae7eac6d3..3e85fae642cd2 100644 --- a/shell/platform/linux/fl_task_runner.h +++ b/shell/platform/linux/fl_task_runner.h @@ -16,8 +16,7 @@ G_DECLARE_FINAL_TYPE(FlTaskRunner, fl_task_runner, FL, TASK_RUNNER, GObject); /** * fl_task_runner_new: - * @executor: Function responsible for executing Flutter tasks. - * @executor_user_data: user data for executor. + * @engine: the #FlEngine owning the task runner. * * Creates new task runner instance. * From f9ab9fb16741d98fdd92ab4d084f08b523f26727 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 6 May 2021 02:06:09 +0200 Subject: [PATCH 11/14] Reorder functions --- shell/platform/linux/fl_task_runner.cc | 100 ++++++++++++------------- 1 file changed, 49 insertions(+), 51 deletions(-) diff --git a/shell/platform/linux/fl_task_runner.cc b/shell/platform/linux/fl_task_runner.cc index 6892479e53299..fc1d09d111e8a 100644 --- a/shell/platform/linux/fl_task_runner.cc +++ b/shell/platform/linux/fl_task_runner.cc @@ -31,54 +31,6 @@ typedef struct _FlTaskRunnerTask { G_DEFINE_TYPE(FlTaskRunner, fl_task_runner, G_TYPE_OBJECT) -static void fl_task_runner_dispose(GObject* object); - -static void fl_task_runner_class_init(FlTaskRunnerClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_task_runner_dispose; -} - -static void fl_task_runner_init(FlTaskRunner* self) { - g_mutex_init(&self->mutex); - g_cond_init(&self->cond); -} - -static void engine_weak_notify_cb(gpointer user_data, - GObject* where_the_object_was) { - FlTaskRunner* self = FL_TASK_RUNNER(user_data); - self->engine = nullptr; -} - -void fl_task_runner_dispose(GObject* object) { - FlTaskRunner* self = FL_TASK_RUNNER(object); - - // this should never happen because the task runner is retained while blocking - // main thread - g_assert(!self->blocking_main_thread); - - if (self->engine != nullptr) { - g_object_weak_unref(G_OBJECT(self->engine), engine_weak_notify_cb, self); - self->engine = nullptr; - } - - g_mutex_clear(&self->mutex); - g_cond_clear(&self->cond); - - g_list_free_full(self->pending_tasks, g_free); - if (self->timeout_source_id != 0) { - g_source_remove(self->timeout_source_id); - } - - G_OBJECT_CLASS(fl_task_runner_parent_class)->dispose(object); -} - -FlTaskRunner* fl_task_runner_new(FlEngine* engine) { - FlTaskRunner* res = - FL_TASK_RUNNER(g_object_new(fl_task_runner_get_type(), nullptr)); - res->engine = engine; - g_object_weak_ref(G_OBJECT(engine), engine_weak_notify_cb, res); - return res; -} - // Removes expired tasks from the task queue and executes them. // The execution is performed with mutex unlocked. static void fl_task_runner_process_expired_tasks_locked(FlTaskRunner* self) { @@ -172,9 +124,50 @@ static void fl_task_runner_tasks_did_change_locked(FlTaskRunner* self) { } } -void fl_task_runner_stop(FlTaskRunner* self) { - // No locking necessary, stop is only set and read on main thread - self->stopped = true; +static void engine_weak_notify_cb(gpointer user_data, + GObject* where_the_object_was) { + FlTaskRunner* self = FL_TASK_RUNNER(user_data); + self->engine = nullptr; +} + +void fl_task_runner_dispose(GObject* object) { + FlTaskRunner* self = FL_TASK_RUNNER(object); + + // this should never happen because the task runner is retained while blocking + // main thread + g_assert(!self->blocking_main_thread); + + if (self->engine != nullptr) { + g_object_weak_unref(G_OBJECT(self->engine), engine_weak_notify_cb, self); + self->engine = nullptr; + } + + g_mutex_clear(&self->mutex); + g_cond_clear(&self->cond); + + g_list_free_full(self->pending_tasks, g_free); + if (self->timeout_source_id != 0) { + g_source_remove(self->timeout_source_id); + } + + G_OBJECT_CLASS(fl_task_runner_parent_class)->dispose(object); +} + +static void fl_task_runner_class_init(FlTaskRunnerClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_task_runner_dispose; +} + +static void fl_task_runner_init(FlTaskRunner* self) { + g_mutex_init(&self->mutex); + g_cond_init(&self->cond); +} + +FlTaskRunner* fl_task_runner_new(FlEngine* engine) { + FlTaskRunner* res = + FL_TASK_RUNNER(g_object_new(fl_task_runner_get_type(), nullptr)); + res->engine = engine; + g_object_weak_ref(G_OBJECT(engine), engine_weak_notify_cb, res); + return res; } void fl_task_runner_post_task(FlTaskRunner* self, @@ -192,6 +185,11 @@ void fl_task_runner_post_task(FlTaskRunner* self, fl_task_runner_tasks_did_change_locked(self); } +void fl_task_runner_stop(FlTaskRunner* self) { + // No locking necessary, stop is only set and read on main thread + self->stopped = true; +} + void fl_task_runner_block_main_thread(FlTaskRunner* self) { g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->mutex); (void)locker; // unused variable From 02520077ac43149a93eecd67a709a234f5749eea Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 6 May 2021 02:20:39 +0200 Subject: [PATCH 12/14] Remove fl_task_runner_stop It was redundant after FlTaskRunner was updated to keep weak reference to engine. --- shell/platform/linux/fl_engine.cc | 2 -- shell/platform/linux/fl_task_runner.cc | 19 +++++-------------- shell/platform/linux/fl_task_runner.h | 10 ---------- 3 files changed, 5 insertions(+), 26 deletions(-) diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 4e8ffa6afb980..8028d21005a58 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -301,8 +301,6 @@ static void fl_engine_dispose(GObject* object) { g_clear_object(&self->renderer); g_clear_object(&self->binary_messenger); g_clear_object(&self->settings_plugin); - - fl_task_runner_stop(self->task_runner); g_clear_object(&self->task_runner); if (self->platform_message_handler_destroy_notify) { diff --git a/shell/platform/linux/fl_task_runner.cc b/shell/platform/linux/fl_task_runner.cc index fc1d09d111e8a..978d4e8dc36a9 100644 --- a/shell/platform/linux/fl_task_runner.cc +++ b/shell/platform/linux/fl_task_runner.cc @@ -19,8 +19,6 @@ struct _FlTaskRunner { guint timeout_source_id; GList /**/* pending_tasks; gboolean blocking_main_thread; - - gboolean stopped; }; typedef struct _FlTaskRunnerTask { @@ -53,13 +51,11 @@ static void fl_task_runner_process_expired_tasks_locked(FlTaskRunner* self) { g_mutex_unlock(&self->mutex); - if (self->engine) { - l = expired_tasks; - while (l != nullptr && !self->stopped) { - FlTaskRunnerTask* task = static_cast(l->data); - fl_engine_execute_task(self->engine, &task->task); - l = l->next; - } + l = expired_tasks; + while (l != nullptr && self->engine) { + FlTaskRunnerTask* task = static_cast(l->data); + fl_engine_execute_task(self->engine, &task->task); + l = l->next; } g_list_free_full(expired_tasks, g_free); @@ -185,11 +181,6 @@ void fl_task_runner_post_task(FlTaskRunner* self, fl_task_runner_tasks_did_change_locked(self); } -void fl_task_runner_stop(FlTaskRunner* self) { - // No locking necessary, stop is only set and read on main thread - self->stopped = true; -} - void fl_task_runner_block_main_thread(FlTaskRunner* self) { g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->mutex); (void)locker; // unused variable diff --git a/shell/platform/linux/fl_task_runner.h b/shell/platform/linux/fl_task_runner.h index 3e85fae642cd2..ca4f84b3ee521 100644 --- a/shell/platform/linux/fl_task_runner.h +++ b/shell/platform/linux/fl_task_runner.h @@ -37,16 +37,6 @@ void fl_task_runner_post_task(FlTaskRunner* task_runner, FlutterTask task, uint64_t target_time_nanos); -/** - * fl_task_runner_stop: - * @task_runner: an #FlTaskRunner. - * - * Requests stop. After this method completes no more tasks will be executed - * by the task runner. Remaining scheduled tasks will be ignored. - * Must be invoked on main thread. - */ -void fl_task_runner_stop(FlTaskRunner* task_runner); - /** * fl_task_runner_block_main_thread: * @task_runner: an #FlTaskRunner. From de05a35479ef33e8463b7400d02c2248fb6fec8d Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 6 May 2021 02:28:36 +0200 Subject: [PATCH 13/14] Typo --- shell/platform/linux/fl_task_runner.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/linux/fl_task_runner.cc b/shell/platform/linux/fl_task_runner.cc index 978d4e8dc36a9..5738ac0d2d2ec 100644 --- a/shell/platform/linux/fl_task_runner.cc +++ b/shell/platform/linux/fl_task_runner.cc @@ -66,7 +66,7 @@ static void fl_task_runner_process_expired_tasks_locked(FlTaskRunner* self) { static void fl_task_runner_tasks_did_change_locked(FlTaskRunner* self); // Invoked from a timeout source. Removes and executes expired tasks -// and rechedules timeout if needed. +// and reschedules timeout if needed. static gboolean fl_task_runner_on_expired_timeout(gpointer data) { FlTaskRunner* self = FL_TASK_RUNNER(data); From e15583a366b5a317b720a9ea487a83ef49a55580 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 6 May 2021 18:55:26 +0200 Subject: [PATCH 14/14] Reschedule timeout when leaving fl_task_runner_block_main_thread --- shell/platform/linux/fl_task_runner.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/shell/platform/linux/fl_task_runner.cc b/shell/platform/linux/fl_task_runner.cc index 5738ac0d2d2ec..ce9938915ccda 100644 --- a/shell/platform/linux/fl_task_runner.cc +++ b/shell/platform/linux/fl_task_runner.cc @@ -196,6 +196,9 @@ void fl_task_runner_block_main_thread(FlTaskRunner* self) { fl_task_runner_process_expired_tasks_locked(self); } + // Tasks might have changed in the meanwhile, reschedule timeout + fl_task_runner_tasks_did_change_locked(self); + g_object_unref(self); }