From 88489bc530c7e29c188965b76ecf5a694d4f39e3 Mon Sep 17 00:00:00 2001 From: moko256 Date: Wed, 11 Aug 2021 17:19:38 +0900 Subject: [PATCH 01/10] Fully inplement TaskRunner for UWP --- shell/platform/windows/task_runner_winuwp.cc | 128 +++++++++++-------- shell/platform/windows/task_runner_winuwp.h | 111 ++++++++-------- 2 files changed, 136 insertions(+), 103 deletions(-) diff --git a/shell/platform/windows/task_runner_winuwp.cc b/shell/platform/windows/task_runner_winuwp.cc index 9f8ebaf3bbd00..247431a1333ef 100644 --- a/shell/platform/windows/task_runner_winuwp.cc +++ b/shell/platform/windows/task_runner_winuwp.cc @@ -1,51 +1,77 @@ -// 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/windows/task_runner_winuwp.h" - -#include -#include - -namespace flutter { - -// static -std::unique_ptr TaskRunner::Create( - DWORD main_thread_id, - CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired) { - return std::make_unique(main_thread_id, on_task_expired); -} - -TaskRunnerWinUwp::TaskRunnerWinUwp(DWORD main_thread_id, - const TaskExpiredCallback& on_task_expired) - : main_thread_id_(main_thread_id), - on_task_expired_(std::move(on_task_expired)) { - dispatcher_ = - winrt::Windows::UI::Core::CoreWindow::GetForCurrentThread().Dispatcher(); -} - -TaskRunnerWinUwp::~TaskRunnerWinUwp() = default; - -bool TaskRunnerWinUwp::RunsTasksOnCurrentThread() const { - return GetCurrentThreadId() == main_thread_id_; -} - -void TaskRunnerWinUwp::PostFlutterTask(FlutterTask flutter_task, - uint64_t flutter_target_time_nanos) { - // TODO: Handle the target time. See - // https://github.com/flutter/flutter/issues/70890. - - dispatcher_.RunAsync( - winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, - [this, flutter_task]() { on_task_expired_(&flutter_task); }); -} - -void TaskRunnerWinUwp::PostTask(TaskClosure task) { - // TODO: Handle the target time. See PostFlutterTask() - - dispatcher_.RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, - [task]() { task(); }); -} - -} // namespace flutter +// 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/windows/task_runner_winuwp.h" + +#include +#include + +namespace flutter { + +// static +std::unique_ptr TaskRunner::Create( + DWORD main_thread_id, + CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired) { + return std::make_unique(main_thread_id, get_current_time, + on_task_expired); +} + +TaskRunnerWinUwp::TaskRunnerWinUwp(DWORD main_thread_id, + CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired) + : main_thread_id_(main_thread_id), + get_current_time_(get_current_time), + on_task_expired_(std::move(on_task_expired)) { + dispatcher_ = + winrt::Windows::UI::Core::CoreWindow::GetForCurrentThread().Dispatcher(); +} + +TaskRunnerWinUwp::~TaskRunnerWinUwp() { + std::lock_guard lock(timer_queued_mutex_); + for (const auto& timer : timer_queued_) { + timer.Cancel(); + } +}; + +bool TaskRunnerWinUwp::RunsTasksOnCurrentThread() const { + return GetCurrentThreadId() == main_thread_id_; +} + +void TaskRunnerWinUwp::PostFlutterTask(FlutterTask flutter_task, + uint64_t flutter_target_time_nanos) { + const auto delay = + std::chrono::duration_cast( + std::chrono::nanoseconds(flutter_target_time_nanos - + get_current_time_())); + + auto timer = winrt::Windows::System::Threading::ThreadPoolTimer::CreateTimer( + winrt::Windows::System::Threading::TimerElapsedHandler( + [this, flutter_task](auto& timer) { + { + std::lock_guard lock(timer_queued_mutex_); + auto i = + std::find(timer_queued_.begin(), timer_queued_.end(), timer); + if (i != timer_queued_.end()) { + timer_queued_.erase(i); + } + } + + PostTask( + [this, flutter_task]() { on_task_expired_(&flutter_task); }); + }), + delay); + + { + std::lock_guard lock(timer_queued_mutex_); + timer_queued_.push_back(timer); + } +} + +void TaskRunnerWinUwp::PostTask(TaskClosure task) { + dispatcher_.RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, + [task]() { task(); }); +} + +} // namespace flutter diff --git a/shell/platform/windows/task_runner_winuwp.h b/shell/platform/windows/task_runner_winuwp.h index 7ee6d196ed91d..96080885879d0 100644 --- a/shell/platform/windows/task_runner_winuwp.h +++ b/shell/platform/windows/task_runner_winuwp.h @@ -1,52 +1,59 @@ -// 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_WINDOWS_WINRT_TASK_RUNNER_H_ -#define FLUTTER_SHELL_PLATFORM_WINDOWS_WINRT_TASK_RUNNER_H_ - -#include - -#include - -#include -#include -#include - -#include "flutter/shell/platform/embedder/embedder.h" -#include "flutter/shell/platform/windows/task_runner.h" - -namespace flutter { - -// A custom task runner that uses a CoreDispatcher to schedule -// flutter tasks. -class TaskRunnerWinUwp : public TaskRunner { - public: - TaskRunnerWinUwp(DWORD main_thread_id, - const TaskExpiredCallback& on_task_expired); - - ~TaskRunnerWinUwp(); - - TaskRunnerWinUwp(const TaskRunnerWinUwp&) = delete; - TaskRunnerWinUwp& operator=(const TaskRunnerWinUwp&) = delete; - - // |TaskRunner| - bool RunsTasksOnCurrentThread() const override; - - // |TaskRunner| - void PostFlutterTask(FlutterTask flutter_task, - uint64_t flutter_target_time_nanos) override; - - // |TaskRunner| - void PostTask(TaskClosure task) override; - - private: - DWORD main_thread_id_; - TaskExpiredCallback on_task_expired_; - - winrt::Windows::UI::Core::CoreDispatcher dispatcher_{nullptr}; -}; - -} // namespace flutter - -#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_WINRT_TASK_RUNNER_H_ +// 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_WINDOWS_WINRT_TASK_RUNNER_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_WINRT_TASK_RUNNER_H_ + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/windows/task_runner.h" + +namespace flutter { + +// A custom task runner that uses a CoreDispatcher to schedule +// flutter tasks. +class TaskRunnerWinUwp : public TaskRunner { + public: + TaskRunnerWinUwp(DWORD main_thread_id, + CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired); + + virtual ~TaskRunnerWinUwp(); + + TaskRunnerWinUwp(const TaskRunnerWinUwp&) = delete; + TaskRunnerWinUwp& operator=(const TaskRunnerWinUwp&) = delete; + + // |TaskRunner| + bool RunsTasksOnCurrentThread() const override; + + // |TaskRunner| + void PostFlutterTask(FlutterTask flutter_task, + uint64_t flutter_target_time_nanos) override; + + // |TaskRunner| + void PostTask(TaskClosure task) override; + + private: + DWORD main_thread_id_; + CurrentTimeProc get_current_time_; + TaskExpiredCallback on_task_expired_; + std::mutex timer_queued_mutex_; + std::vector timer_queued_; + + winrt::Windows::UI::Core::CoreDispatcher dispatcher_{nullptr}; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_WINRT_TASK_RUNNER_H_ From bed8757e438f39559e6320e36cae309c5932d601 Mon Sep 17 00:00:00 2001 From: moko256 Date: Wed, 8 Sep 2021 10:07:58 +0900 Subject: [PATCH 02/10] implement TaskRunner with DispatcherQueue for UWP --- shell/platform/windows/BUILD.gn | 1 + .../windows/flutter_windows_engine.cc | 5 +- shell/platform/windows/task_runner.cc | 110 ++++++++++++++++ shell/platform/windows/task_runner.h | 83 +++++++++--- shell/platform/windows/task_runner_win32.cc | 119 +++--------------- shell/platform/windows/task_runner_win32.h | 71 ++--------- shell/platform/windows/task_runner_winuwp.cc | 85 +++++-------- shell/platform/windows/task_runner_winuwp.h | 52 +++----- 8 files changed, 258 insertions(+), 268 deletions(-) create mode 100644 shell/platform/windows/task_runner.cc diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index 525e852577b6b..caeda85ed3a12 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -77,6 +77,7 @@ source_set("flutter_windows_source") { "sequential_id_generator.cc", "sequential_id_generator.h", "system_utils.h", + "task_runner.cc", "task_runner.h", "text_input_plugin.cc", "text_input_plugin.h", diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index 71897bc727f68..cec9b3d6392ff 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -142,9 +142,8 @@ FlutterWindowsEngine::FlutterWindowsEngine(const FlutterProjectBundle& project) embedder_api_.struct_size = sizeof(FlutterEngineProcTable); FlutterEngineGetProcAddresses(&embedder_api_); - task_runner_ = TaskRunner::Create( - GetCurrentThreadId(), embedder_api_.GetCurrentTime, - [this](const auto* task) { + task_runner_ = std::make_unique( + embedder_api_.GetCurrentTime, [this](const auto* task) { if (!engine_) { std::cerr << "Cannot post an engine task when engine is not running." << std::endl; diff --git a/shell/platform/windows/task_runner.cc b/shell/platform/windows/task_runner.cc new file mode 100644 index 0000000000000..8e7faba99e3e9 --- /dev/null +++ b/shell/platform/windows/task_runner.cc @@ -0,0 +1,110 @@ +// 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/windows/task_runner.h" + +#include +#include + +namespace flutter { + +TaskRunner::TaskRunner(CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired) + : get_current_time_(get_current_time), + on_task_expired_(std::move(on_task_expired)) { + timer_ = TaskRunnerTimer::Create(this); +} + +bool TaskRunner::RunsTasksOnCurrentThread() const { + return timer_->RunsOnCurrentThread(); +} + +std::chrono::nanoseconds TaskRunner::ProcessTasks() { + const TaskTimePoint now = TaskTimePoint::clock::now(); + + std::vector expired_tasks; + + // Process expired tasks. + { + std::lock_guard lock(task_queue_mutex_); + while (!task_queue_.empty()) { + const auto& top = task_queue_.top(); + // If this task (and all tasks after this) has not yet expired, there is + // nothing more to do. Quit iterating. + if (top.fire_time > now) { + break; + } + + // Make a record of the expired task. Do NOT service the task here + // because we are still holding onto the task queue mutex. We don't want + // other threads to block on posting tasks onto this thread till we are + // done processing expired tasks. + expired_tasks.push_back(task_queue_.top()); + + // Remove the tasks from the delayed tasks queue. + task_queue_.pop(); + } + } + + // Fire expired tasks. + { + // Flushing tasks here without holing onto the task queue mutex. + for (const auto& task : expired_tasks) { + if (auto flutter_task = std::get_if(&task.variant)) { + on_task_expired_(flutter_task); + } else if (auto closure = std::get_if(&task.variant)) + (*closure)(); + } + } + + // Calculate duration to sleep for on next iteration. + { + std::lock_guard lock(task_queue_mutex_); + const auto next_wake = task_queue_.empty() ? TaskTimePoint::max() + : task_queue_.top().fire_time; + + return std::min(next_wake - now, std::chrono::nanoseconds::max()); + } +} + +TaskRunner::TaskTimePoint TaskRunner::TimePointFromFlutterTime( + uint64_t flutter_target_time_nanos) const { + const auto now = TaskTimePoint::clock::now(); + const auto flutter_duration = flutter_target_time_nanos - get_current_time_(); + return now + std::chrono::nanoseconds(flutter_duration); +} + +void TaskRunner::PostFlutterTask(FlutterTask flutter_task, + uint64_t flutter_target_time_nanos) { + Task task; + task.fire_time = TimePointFromFlutterTime(flutter_target_time_nanos); + task.variant = flutter_task; + EnqueueTask(std::move(task)); +} + +void TaskRunner::PostTask(TaskClosure closure) { + Task task; + task.fire_time = TaskTimePoint::clock::now(); + task.variant = std::move(closure); + EnqueueTask(std::move(task)); +} + +void TaskRunner::EnqueueTask(Task task) { + static std::atomic_uint64_t sGlobalTaskOrder(0); + + task.order = ++sGlobalTaskOrder; + { + std::lock_guard lock(task_queue_mutex_); + task_queue_.push(task); + + // Make sure the queue mutex is unlocked before waking up the loop. In case + // the wake causes this thread to be descheduled for the primary thread to + // process tasks, the acquisition of the lock on that thread while holding + // the lock here momentarily till the end of the scope is a pessimization. + } + + timer_->WakeUp(); +} + +} // namespace flutter diff --git a/shell/platform/windows/task_runner.h b/shell/platform/windows/task_runner.h index 0e3d44450281e..dd90a68dd997b 100644 --- a/shell/platform/windows/task_runner.h +++ b/shell/platform/windows/task_runner.h @@ -5,10 +5,13 @@ #ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_H_ #define FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_H_ -#include - #include +#include +#include #include +#include +#include +#include #include "flutter/shell/platform/embedder/embedder.h" @@ -16,24 +19,47 @@ namespace flutter { typedef uint64_t (*CurrentTimeProc)(); -// Abstract custom task runner for scheduling custom tasks. -class TaskRunner { +// Abstract custom timer. +class TaskRunnerTimer { + public: + class Delegate { + public: + virtual std::chrono::nanoseconds ProcessTasks() = 0; + }; + + virtual void WakeUp() = 0; + + virtual bool RunsOnCurrentThread() const = 0; + + virtual ~TaskRunnerTimer() = default; + + // Creates a new timer with the current thread. + static std::unique_ptr Create(Delegate* delegate); +}; + +class TaskRunner : public TaskRunnerTimer::Delegate { public: using TaskTimePoint = std::chrono::steady_clock::time_point; using TaskExpiredCallback = std::function; using TaskClosure = std::function; - virtual ~TaskRunner() = default; + // Creates a new task runner with the current thread, current time + // provider, and callback for tasks that are ready to be run. + TaskRunner(CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired); // Returns if the current thread is the UI thread. - virtual bool RunsTasksOnCurrentThread() const = 0; + bool RunsTasksOnCurrentThread() const; // Post a Flutter engine task to the event loop for delayed execution. - virtual void PostFlutterTask(FlutterTask flutter_task, - uint64_t flutter_target_time_nanos) = 0; + void PostFlutterTask(FlutterTask flutter_task, + uint64_t flutter_target_time_nanos); // Post a task to the event loop. - virtual void PostTask(TaskClosure task) = 0; + void PostTask(TaskClosure task); + + // |TaskRunnerTimer::Delegate| + std::chrono::nanoseconds ProcessTasks() override; // Post a task to the event loop or run it immediately if this is being called // from the main thread. @@ -45,12 +71,39 @@ class TaskRunner { } } - // Creates a new task runner with the given main thread ID, current time - // provider, and callback for tasks that are ready to be run. - static std::unique_ptr Create( - DWORD main_thread_id, - CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired); + private: + typedef std::variant TaskVariant; + + struct Task { + uint64_t order; + TaskTimePoint fire_time; + TaskVariant variant; + + struct Comparer { + bool operator()(const Task& a, const Task& b) { + if (a.fire_time == b.fire_time) { + return a.order > b.order; + } + return a.fire_time > b.fire_time; + } + }; + }; + + // Enqueues the given task. + void EnqueueTask(Task task); + + // Returns a TaskTimePoint computed from the given target time from Flutter. + TaskTimePoint TimePointFromFlutterTime( + uint64_t flutter_target_time_nanos) const; + + CurrentTimeProc get_current_time_; + TaskExpiredCallback on_task_expired_; + std::mutex task_queue_mutex_; + std::priority_queue, Task::Comparer> task_queue_; + std::unique_ptr timer_; + + TaskRunner(const TaskRunner&) = delete; + TaskRunner& operator=(const TaskRunner&) = delete; }; } // namespace flutter diff --git a/shell/platform/windows/task_runner_win32.cc b/shell/platform/windows/task_runner_win32.cc index 62de4a1567d16..db6f9aaea46cb 100644 --- a/shell/platform/windows/task_runner_win32.cc +++ b/shell/platform/windows/task_runner_win32.cc @@ -4,124 +4,35 @@ #include "flutter/shell/platform/windows/task_runner_win32.h" -#include -#include -#include - namespace flutter { // static -std::unique_ptr TaskRunner::Create( - DWORD main_thread_id, - CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired) { - return std::make_unique(main_thread_id, get_current_time, - on_task_expired); +std::unique_ptr TaskRunnerTimer::Create( + TaskRunnerTimer::Delegate* delegate) { + return std::make_unique(delegate); } -TaskRunnerWin32::TaskRunnerWin32(DWORD main_thread_id, - CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired) - : main_thread_id_(main_thread_id), - get_current_time_(get_current_time), - on_task_expired_(std::move(on_task_expired)) { +TaskRunnerTimerWin32::TaskRunnerTimerWin32(TaskRunnerTimer::Delegate* delegate) + : delegate_(delegate) { + main_thread_id_ = GetCurrentThreadId(); task_runner_window_ = TaskRunnerWin32Window::GetSharedInstance(); task_runner_window_->AddDelegate(this); } -TaskRunnerWin32::~TaskRunnerWin32() { +TaskRunnerTimerWin32::~TaskRunnerTimerWin32() { task_runner_window_->RemoveDelegate(this); } -bool TaskRunnerWin32::RunsTasksOnCurrentThread() const { - return GetCurrentThreadId() == main_thread_id_; -} - -std::chrono::nanoseconds TaskRunnerWin32::ProcessTasks() { - const TaskTimePoint now = TaskTimePoint::clock::now(); - - std::vector expired_tasks; - - // Process expired tasks. - { - std::lock_guard lock(task_queue_mutex_); - while (!task_queue_.empty()) { - const auto& top = task_queue_.top(); - // If this task (and all tasks after this) has not yet expired, there is - // nothing more to do. Quit iterating. - if (top.fire_time > now) { - break; - } - - // Make a record of the expired task. Do NOT service the task here - // because we are still holding onto the task queue mutex. We don't want - // other threads to block on posting tasks onto this thread till we are - // done processing expired tasks. - expired_tasks.push_back(task_queue_.top()); - - // Remove the tasks from the delayed tasks queue. - task_queue_.pop(); - } - } - - // Fire expired tasks. - { - // Flushing tasks here without holing onto the task queue mutex. - for (const auto& task : expired_tasks) { - if (auto flutter_task = std::get_if(&task.variant)) { - on_task_expired_(flutter_task); - } else if (auto closure = std::get_if(&task.variant)) - (*closure)(); - } - } - - // Calculate duration to sleep for on next iteration. - { - std::lock_guard lock(task_queue_mutex_); - const auto next_wake = task_queue_.empty() ? TaskTimePoint::max() - : task_queue_.top().fire_time; - - return std::min(next_wake - now, std::chrono::nanoseconds::max()); - } -} - -TaskRunnerWin32::TaskTimePoint TaskRunnerWin32::TimePointFromFlutterTime( - uint64_t flutter_target_time_nanos) const { - const auto now = TaskTimePoint::clock::now(); - const auto flutter_duration = flutter_target_time_nanos - get_current_time_(); - return now + std::chrono::nanoseconds(flutter_duration); -} - -void TaskRunnerWin32::PostFlutterTask(FlutterTask flutter_task, - uint64_t flutter_target_time_nanos) { - Task task; - task.fire_time = TimePointFromFlutterTime(flutter_target_time_nanos); - task.variant = flutter_task; - EnqueueTask(std::move(task)); -} - -void TaskRunnerWin32::PostTask(TaskClosure closure) { - Task task; - task.fire_time = TaskTimePoint::clock::now(); - task.variant = std::move(closure); - EnqueueTask(std::move(task)); -} - -void TaskRunnerWin32::EnqueueTask(Task task) { - static std::atomic_uint64_t sGlobalTaskOrder(0); - - task.order = ++sGlobalTaskOrder; - { - std::lock_guard lock(task_queue_mutex_); - task_queue_.push(task); +void TaskRunnerTimerWin32::WakeUp() { + task_runner_window_->WakeUp(); +}; - // Make sure the queue mutex is unlocked before waking up the loop. In case - // the wake causes this thread to be descheduled for the primary thread to - // process tasks, the acquisition of the lock on that thread while holding - // the lock here momentarily till the end of the scope is a pessimization. - } +bool TaskRunnerTimerWin32::RunsOnCurrentThread() const { + return GetCurrentThreadId() == main_thread_id_; +}; - task_runner_window_->WakeUp(); +std::chrono::nanoseconds TaskRunnerTimerWin32::ProcessTasks() { + return delegate_->ProcessTasks(); } } // namespace flutter diff --git a/shell/platform/windows/task_runner_win32.h b/shell/platform/windows/task_runner_win32.h index 149e9acd6a67e..4f708ab185704 100644 --- a/shell/platform/windows/task_runner_win32.h +++ b/shell/platform/windows/task_runner_win32.h @@ -7,82 +7,37 @@ #include -#include -#include -#include -#include -#include -#include -#include - #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/windows/task_runner.h" #include "flutter/shell/platform/windows/task_runner_win32_window.h" namespace flutter { -// A custom task runner that integrates with user32 GetMessage semantics so that +// A custom timer that integrates with user32 GetMessage semantics so that // host app can own its own message loop and flutter still gets to process // tasks on a timely basis. -class TaskRunnerWin32 : public TaskRunner, - public TaskRunnerWin32Window::Delegate { +class TaskRunnerTimerWin32 : public TaskRunnerTimer, + public TaskRunnerWin32Window::Delegate { public: - // Creates a new task runner with the given main thread ID, current time - // provider, and callback for tasks that are ready to be run. - TaskRunnerWin32(DWORD main_thread_id, - CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired); - - virtual ~TaskRunnerWin32(); - - // |TaskRunner| - bool RunsTasksOnCurrentThread() const override; + TaskRunnerTimerWin32(TaskRunnerTimer::Delegate* delegate); + virtual ~TaskRunnerTimerWin32(); - // |TaskRunner| - void PostFlutterTask(FlutterTask flutter_task, - uint64_t flutter_target_time_nanos) override; + // |TaskRunnerTimer| + void WakeUp() override; - // |TaskRunner| - void PostTask(TaskClosure task) override; + // |TaskRunnerTimer| + bool RunsOnCurrentThread() const override; - // |TaskRunnerWin32Window::Delegate| + // |TaskRunnerTimer| std::chrono::nanoseconds ProcessTasks() override; private: - typedef std::variant TaskVariant; - - struct Task { - uint64_t order; - TaskTimePoint fire_time; - TaskVariant variant; - - struct Comparer { - bool operator()(const Task& a, const Task& b) { - if (a.fire_time == b.fire_time) { - return a.order > b.order; - } - return a.fire_time > b.fire_time; - } - }; - }; - - // Enqueues the given task. - void EnqueueTask(Task task); - - // Returns a TaskTimePoint computed from the given target time from Flutter. - TaskTimePoint TimePointFromFlutterTime( - uint64_t flutter_target_time_nanos) const; - + TaskRunnerTimer::Delegate* delegate_; DWORD main_thread_id_; - CurrentTimeProc get_current_time_; - TaskExpiredCallback on_task_expired_; - std::mutex task_queue_mutex_; - std::priority_queue, Task::Comparer> task_queue_; std::shared_ptr task_runner_window_; - TaskRunnerWin32(const TaskRunnerWin32&) = delete; - - TaskRunnerWin32& operator=(const TaskRunnerWin32&) = delete; + TaskRunnerTimerWin32(const TaskRunnerTimerWin32&) = delete; + TaskRunnerTimerWin32& operator=(const TaskRunnerTimerWin32&) = delete; }; } // namespace flutter diff --git a/shell/platform/windows/task_runner_winuwp.cc b/shell/platform/windows/task_runner_winuwp.cc index 247431a1333ef..4aeaf7e38064e 100644 --- a/shell/platform/windows/task_runner_winuwp.cc +++ b/shell/platform/windows/task_runner_winuwp.cc @@ -4,74 +4,49 @@ #include "flutter/shell/platform/windows/task_runner_winuwp.h" -#include -#include - namespace flutter { // static -std::unique_ptr TaskRunner::Create( - DWORD main_thread_id, - CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired) { - return std::make_unique(main_thread_id, get_current_time, - on_task_expired); +std::unique_ptr TaskRunnerTimer::Create( + TaskRunnerTimer::Delegate* delegate) { + return std::make_unique(delegate); } -TaskRunnerWinUwp::TaskRunnerWinUwp(DWORD main_thread_id, - CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired) - : main_thread_id_(main_thread_id), - get_current_time_(get_current_time), - on_task_expired_(std::move(on_task_expired)) { - dispatcher_ = - winrt::Windows::UI::Core::CoreWindow::GetForCurrentThread().Dispatcher(); +TaskRunnerTimerWinUwp::TaskRunnerTimerWinUwp( + TaskRunnerTimer::Delegate* delegate) + : delegate_(delegate) { + dispatcher_queue_ = + winrt::Windows::System::DispatcherQueue::GetForCurrentThread(); + dispatcher_queue_timer_ = dispatcher_queue_.CreateTimer(); + dispatcher_queue_timer_.Tick({this, &TaskRunnerTimerWinUwp::OnTick}); } -TaskRunnerWinUwp::~TaskRunnerWinUwp() { - std::lock_guard lock(timer_queued_mutex_); - for (const auto& timer : timer_queued_) { - timer.Cancel(); - } -}; +TaskRunnerTimerWinUwp::~TaskRunnerTimerWinUwp() = default; -bool TaskRunnerWinUwp::RunsTasksOnCurrentThread() const { - return GetCurrentThreadId() == main_thread_id_; -} +void TaskRunnerTimerWinUwp::WakeUp() { + dispatcher_queue_.TryEnqueue([this]() { ProcessTasks(); }); +}; -void TaskRunnerWinUwp::PostFlutterTask(FlutterTask flutter_task, - uint64_t flutter_target_time_nanos) { - const auto delay = - std::chrono::duration_cast( - std::chrono::nanoseconds(flutter_target_time_nanos - - get_current_time_())); +bool TaskRunnerTimerWinUwp::RunsOnCurrentThread() const { + return dispatcher_queue_.HasThreadAccess(); +}; - auto timer = winrt::Windows::System::Threading::ThreadPoolTimer::CreateTimer( - winrt::Windows::System::Threading::TimerElapsedHandler( - [this, flutter_task](auto& timer) { - { - std::lock_guard lock(timer_queued_mutex_); - auto i = - std::find(timer_queued_.begin(), timer_queued_.end(), timer); - if (i != timer_queued_.end()) { - timer_queued_.erase(i); - } - } +void TaskRunnerTimerWinUwp::OnTick( + winrt::Windows::System::DispatcherQueueTimer const&, + winrt::Windows::Foundation::IInspectable const&) { + ProcessTasks(); +} - PostTask( - [this, flutter_task]() { on_task_expired_(&flutter_task); }); - }), - delay); +void TaskRunnerTimerWinUwp::ProcessTasks() { + auto next = delegate_->ProcessTasks(); - { - std::lock_guard lock(timer_queued_mutex_); - timer_queued_.push_back(timer); + if (next == std::chrono::nanoseconds::max()) { + dispatcher_queue_timer_.Stop(); + } else { + dispatcher_queue_timer_.Interval( + std::chrono::duration_cast(next)); + dispatcher_queue_timer_.Start(); } } -void TaskRunnerWinUwp::PostTask(TaskClosure task) { - dispatcher_.RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, - [task]() { task(); }); -} - } // namespace flutter diff --git a/shell/platform/windows/task_runner_winuwp.h b/shell/platform/windows/task_runner_winuwp.h index 96080885879d0..78164a355ea80 100644 --- a/shell/platform/windows/task_runner_winuwp.h +++ b/shell/platform/windows/task_runner_winuwp.h @@ -5,53 +5,39 @@ #ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_WINRT_TASK_RUNNER_H_ #define FLUTTER_SHELL_PLATFORM_WINDOWS_WINRT_TASK_RUNNER_H_ -#include - -#include -#include - -#include -#include -#include -#include -#include +#include +#include #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/windows/task_runner.h" namespace flutter { -// A custom task runner that uses a CoreDispatcher to schedule -// flutter tasks. -class TaskRunnerWinUwp : public TaskRunner { +// A custom timer that uses a DispatcherQueue. +class TaskRunnerTimerWinUwp : public TaskRunnerTimer { public: - TaskRunnerWinUwp(DWORD main_thread_id, - CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired); + TaskRunnerTimerWinUwp(TaskRunnerTimer::Delegate* delegate); + virtual ~TaskRunnerTimerWinUwp(); - virtual ~TaskRunnerWinUwp(); + // |TaskRunnerTimer| + void WakeUp() override; - TaskRunnerWinUwp(const TaskRunnerWinUwp&) = delete; - TaskRunnerWinUwp& operator=(const TaskRunnerWinUwp&) = delete; + // |TaskRunnerTimer| + bool RunsOnCurrentThread() const override; - // |TaskRunner| - bool RunsTasksOnCurrentThread() const override; + private: + void OnTick(winrt::Windows::System::DispatcherQueueTimer const&, + winrt::Windows::Foundation::IInspectable const&); - // |TaskRunner| - void PostFlutterTask(FlutterTask flutter_task, - uint64_t flutter_target_time_nanos) override; + void ProcessTasks(); - // |TaskRunner| - void PostTask(TaskClosure task) override; + TaskRunnerTimer::Delegate* delegate_; - private: - DWORD main_thread_id_; - CurrentTimeProc get_current_time_; - TaskExpiredCallback on_task_expired_; - std::mutex timer_queued_mutex_; - std::vector timer_queued_; + winrt::Windows::System::DispatcherQueue dispatcher_queue_{nullptr}; + winrt::Windows::System::DispatcherQueueTimer dispatcher_queue_timer_{nullptr}; - winrt::Windows::UI::Core::CoreDispatcher dispatcher_{nullptr}; + TaskRunnerTimerWinUwp(const TaskRunnerTimerWinUwp&) = delete; + TaskRunnerTimerWinUwp& operator=(const TaskRunnerTimerWinUwp&) = delete; }; } // namespace flutter From 3d85b13f979e28433527d8a1d63e8a82010ef1fc Mon Sep 17 00:00:00 2001 From: moko256 Date: Mon, 4 Oct 2021 21:47:07 +0900 Subject: [PATCH 03/10] add and update documenets --- shell/platform/windows/task_runner.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/shell/platform/windows/task_runner.h b/shell/platform/windows/task_runner.h index dd90a68dd997b..9c5bb5d8a25f4 100644 --- a/shell/platform/windows/task_runner.h +++ b/shell/platform/windows/task_runner.h @@ -24,11 +24,15 @@ class TaskRunnerTimer { public: class Delegate { public: + // Executes expired task, and returns the duration until the next task + // deadline if exists, otherwise returns `std::chrono::nanoseconds::max()`. virtual std::chrono::nanoseconds ProcessTasks() = 0; }; + // Schedules timers to call ProcessTasks at the timer's thread. virtual void WakeUp() = 0; + // Returns `true` if the current thread is this timer's thread. virtual bool RunsOnCurrentThread() const = 0; virtual ~TaskRunnerTimer() = default; @@ -48,7 +52,7 @@ class TaskRunner : public TaskRunnerTimer::Delegate { TaskRunner(CurrentTimeProc get_current_time, const TaskExpiredCallback& on_task_expired); - // Returns if the current thread is the UI thread. + // Returns `true` if the current thread is this runner's thread. bool RunsTasksOnCurrentThread() const; // Post a Flutter engine task to the event loop for delayed execution. From 50f441e88253728c02ecdd130697d485296f2972 Mon Sep 17 00:00:00 2001 From: moko256 Date: Wed, 13 Oct 2021 08:34:00 +0900 Subject: [PATCH 04/10] use extending insead of delegating --- .../windows/flutter_windows_engine.cc | 2 +- shell/platform/windows/task_runner.cc | 10 +--- shell/platform/windows/task_runner.h | 56 ++++++++----------- shell/platform/windows/task_runner_win32.cc | 28 +++++----- shell/platform/windows/task_runner_win32.h | 29 +++++----- shell/platform/windows/task_runner_winuwp.cc | 31 +++++----- shell/platform/windows/task_runner_winuwp.h | 26 ++++----- 7 files changed, 85 insertions(+), 97 deletions(-) diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index cec9b3d6392ff..c21a67cd102ac 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -142,7 +142,7 @@ FlutterWindowsEngine::FlutterWindowsEngine(const FlutterProjectBundle& project) embedder_api_.struct_size = sizeof(FlutterEngineProcTable); FlutterEngineGetProcAddresses(&embedder_api_); - task_runner_ = std::make_unique( + task_runner_ = TaskRunner::Create( embedder_api_.GetCurrentTime, [this](const auto* task) { if (!engine_) { std::cerr << "Cannot post an engine task when engine is not running." diff --git a/shell/platform/windows/task_runner.cc b/shell/platform/windows/task_runner.cc index 8e7faba99e3e9..fa8b1348c9edd 100644 --- a/shell/platform/windows/task_runner.cc +++ b/shell/platform/windows/task_runner.cc @@ -12,13 +12,7 @@ namespace flutter { TaskRunner::TaskRunner(CurrentTimeProc get_current_time, const TaskExpiredCallback& on_task_expired) : get_current_time_(get_current_time), - on_task_expired_(std::move(on_task_expired)) { - timer_ = TaskRunnerTimer::Create(this); -} - -bool TaskRunner::RunsTasksOnCurrentThread() const { - return timer_->RunsOnCurrentThread(); -} + on_task_expired_(std::move(on_task_expired)) {} std::chrono::nanoseconds TaskRunner::ProcessTasks() { const TaskTimePoint now = TaskTimePoint::clock::now(); @@ -104,7 +98,7 @@ void TaskRunner::EnqueueTask(Task task) { // the lock here momentarily till the end of the scope is a pessimization. } - timer_->WakeUp(); + WakeUp(); } } // namespace flutter diff --git a/shell/platform/windows/task_runner.h b/shell/platform/windows/task_runner.h index 9c5bb5d8a25f4..7f181d0758975 100644 --- a/shell/platform/windows/task_runner.h +++ b/shell/platform/windows/task_runner.h @@ -19,41 +19,16 @@ namespace flutter { typedef uint64_t (*CurrentTimeProc)(); -// Abstract custom timer. -class TaskRunnerTimer { - public: - class Delegate { - public: - // Executes expired task, and returns the duration until the next task - // deadline if exists, otherwise returns `std::chrono::nanoseconds::max()`. - virtual std::chrono::nanoseconds ProcessTasks() = 0; - }; - - // Schedules timers to call ProcessTasks at the timer's thread. - virtual void WakeUp() = 0; - - // Returns `true` if the current thread is this timer's thread. - virtual bool RunsOnCurrentThread() const = 0; - - virtual ~TaskRunnerTimer() = default; - - // Creates a new timer with the current thread. - static std::unique_ptr Create(Delegate* delegate); -}; - -class TaskRunner : public TaskRunnerTimer::Delegate { +class TaskRunner { public: using TaskTimePoint = std::chrono::steady_clock::time_point; using TaskExpiredCallback = std::function; using TaskClosure = std::function; - // Creates a new task runner with the current thread, current time - // provider, and callback for tasks that are ready to be run. - TaskRunner(CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired); + virtual ~TaskRunner() = default; // Returns `true` if the current thread is this runner's thread. - bool RunsTasksOnCurrentThread() const; + virtual bool RunsTasksOnCurrentThread() const = 0; // Post a Flutter engine task to the event loop for delayed execution. void PostFlutterTask(FlutterTask flutter_task, @@ -62,11 +37,8 @@ class TaskRunner : public TaskRunnerTimer::Delegate { // Post a task to the event loop. void PostTask(TaskClosure task); - // |TaskRunnerTimer::Delegate| - std::chrono::nanoseconds ProcessTasks() override; - // Post a task to the event loop or run it immediately if this is being called - // from the main thread. + // from the runner's thread. void RunNowOrPostTask(TaskClosure task) { if (RunsTasksOnCurrentThread()) { task(); @@ -75,6 +47,25 @@ class TaskRunner : public TaskRunnerTimer::Delegate { } } + // Creates a new task runner with the current thread, current time + // provider, and callback for tasks that are ready to be run. + static std::unique_ptr Create( + CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired); + + protected: + TaskRunner(CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired); + + // Schedules timers to call `ProcessTasks()` at the runner's thread. + virtual void WakeUp() = 0; + + // Executes expired task, and returns the duration until the next task + // deadline if exists, otherwise returns `std::chrono::nanoseconds::max()`. + // + // Each platform implementations must call this to schedule the tasks. + std::chrono::nanoseconds ProcessTasks(); + private: typedef std::variant TaskVariant; @@ -104,7 +95,6 @@ class TaskRunner : public TaskRunnerTimer::Delegate { TaskExpiredCallback on_task_expired_; std::mutex task_queue_mutex_; std::priority_queue, Task::Comparer> task_queue_; - std::unique_ptr timer_; TaskRunner(const TaskRunner&) = delete; TaskRunner& operator=(const TaskRunner&) = delete; diff --git a/shell/platform/windows/task_runner_win32.cc b/shell/platform/windows/task_runner_win32.cc index db6f9aaea46cb..1fe72cf7e3f58 100644 --- a/shell/platform/windows/task_runner_win32.cc +++ b/shell/platform/windows/task_runner_win32.cc @@ -7,32 +7,34 @@ namespace flutter { // static -std::unique_ptr TaskRunnerTimer::Create( - TaskRunnerTimer::Delegate* delegate) { - return std::make_unique(delegate); +std::unique_ptr TaskRunner::Create( + CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired) { + return std::make_unique(get_current_time, on_task_expired); } -TaskRunnerTimerWin32::TaskRunnerTimerWin32(TaskRunnerTimer::Delegate* delegate) - : delegate_(delegate) { +TaskRunnerWin32::TaskRunnerWin32(CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired) + : TaskRunner(get_current_time, on_task_expired) { main_thread_id_ = GetCurrentThreadId(); task_runner_window_ = TaskRunnerWin32Window::GetSharedInstance(); task_runner_window_->AddDelegate(this); } -TaskRunnerTimerWin32::~TaskRunnerTimerWin32() { +TaskRunnerWin32::~TaskRunnerWin32() { task_runner_window_->RemoveDelegate(this); } -void TaskRunnerTimerWin32::WakeUp() { - task_runner_window_->WakeUp(); -}; - -bool TaskRunnerTimerWin32::RunsOnCurrentThread() const { +bool TaskRunnerWin32::RunsTasksOnCurrentThread() const { return GetCurrentThreadId() == main_thread_id_; }; -std::chrono::nanoseconds TaskRunnerTimerWin32::ProcessTasks() { - return delegate_->ProcessTasks(); +std::chrono::nanoseconds TaskRunnerWin32::ProcessTasks() { + return TaskRunner::ProcessTasks(); } +void TaskRunnerWin32::WakeUp() { + task_runner_window_->WakeUp(); +}; + } // namespace flutter diff --git a/shell/platform/windows/task_runner_win32.h b/shell/platform/windows/task_runner_win32.h index 4f708ab185704..6e3ceb8476f63 100644 --- a/shell/platform/windows/task_runner_win32.h +++ b/shell/platform/windows/task_runner_win32.h @@ -13,31 +13,32 @@ namespace flutter { -// A custom timer that integrates with user32 GetMessage semantics so that +// A custom task runner that integrates with user32 GetMessage semantics so that // host app can own its own message loop and flutter still gets to process // tasks on a timely basis. -class TaskRunnerTimerWin32 : public TaskRunnerTimer, - public TaskRunnerWin32Window::Delegate { +class TaskRunnerWin32 : public TaskRunner, + public TaskRunnerWin32Window::Delegate { public: - TaskRunnerTimerWin32(TaskRunnerTimer::Delegate* delegate); - virtual ~TaskRunnerTimerWin32(); + TaskRunnerWin32(CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired); + virtual ~TaskRunnerWin32(); - // |TaskRunnerTimer| - void WakeUp() override; - - // |TaskRunnerTimer| - bool RunsOnCurrentThread() const override; + // |TaskRunner| + bool RunsTasksOnCurrentThread() const override; - // |TaskRunnerTimer| + // |TaskRunnerWin32Window::Delegate| std::chrono::nanoseconds ProcessTasks() override; + protected: + // |TaskRunner| + void WakeUp() override; + private: - TaskRunnerTimer::Delegate* delegate_; DWORD main_thread_id_; std::shared_ptr task_runner_window_; - TaskRunnerTimerWin32(const TaskRunnerTimerWin32&) = delete; - TaskRunnerTimerWin32& operator=(const TaskRunnerTimerWin32&) = delete; + TaskRunnerWin32(const TaskRunnerWin32&) = delete; + TaskRunnerWin32& operator=(const TaskRunnerWin32&) = delete; }; } // namespace flutter diff --git a/shell/platform/windows/task_runner_winuwp.cc b/shell/platform/windows/task_runner_winuwp.cc index 4aeaf7e38064e..e74e0551a600e 100644 --- a/shell/platform/windows/task_runner_winuwp.cc +++ b/shell/platform/windows/task_runner_winuwp.cc @@ -7,38 +7,39 @@ namespace flutter { // static -std::unique_ptr TaskRunnerTimer::Create( - TaskRunnerTimer::Delegate* delegate) { - return std::make_unique(delegate); +std::unique_ptr TaskRunner::Create( + CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired) { + return std::make_unique(get_current_time, on_task_expired); } -TaskRunnerTimerWinUwp::TaskRunnerTimerWinUwp( - TaskRunnerTimer::Delegate* delegate) - : delegate_(delegate) { +TaskRunnerWinUwp::TaskRunnerWinUwp(CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired) + : TaskRunner(get_current_time, on_task_expired) { dispatcher_queue_ = winrt::Windows::System::DispatcherQueue::GetForCurrentThread(); dispatcher_queue_timer_ = dispatcher_queue_.CreateTimer(); - dispatcher_queue_timer_.Tick({this, &TaskRunnerTimerWinUwp::OnTick}); + dispatcher_queue_timer_.Tick({this, &TaskRunnerWinUwp::OnTick}); } -TaskRunnerTimerWinUwp::~TaskRunnerTimerWinUwp() = default; +TaskRunnerWinUwp::~TaskRunnerWinUwp() = default; -void TaskRunnerTimerWinUwp::WakeUp() { - dispatcher_queue_.TryEnqueue([this]() { ProcessTasks(); }); +bool TaskRunnerWinUwp::RunsTasksOnCurrentThread() const { + return dispatcher_queue_.HasThreadAccess(); }; -bool TaskRunnerTimerWinUwp::RunsOnCurrentThread() const { - return dispatcher_queue_.HasThreadAccess(); +void TaskRunnerWinUwp::WakeUp() { + dispatcher_queue_.TryEnqueue([this]() { ProcessTasksAndScheduleNext(); }); }; -void TaskRunnerTimerWinUwp::OnTick( +void TaskRunnerWinUwp::OnTick( winrt::Windows::System::DispatcherQueueTimer const&, winrt::Windows::Foundation::IInspectable const&) { ProcessTasks(); } -void TaskRunnerTimerWinUwp::ProcessTasks() { - auto next = delegate_->ProcessTasks(); +void TaskRunnerWinUwp::ProcessTasksAndScheduleNext() { + auto next = ProcessTasks(); if (next == std::chrono::nanoseconds::max()) { dispatcher_queue_timer_.Stop(); diff --git a/shell/platform/windows/task_runner_winuwp.h b/shell/platform/windows/task_runner_winuwp.h index 78164a355ea80..b1d7e524a2f80 100644 --- a/shell/platform/windows/task_runner_winuwp.h +++ b/shell/platform/windows/task_runner_winuwp.h @@ -13,31 +13,31 @@ namespace flutter { -// A custom timer that uses a DispatcherQueue. -class TaskRunnerTimerWinUwp : public TaskRunnerTimer { +// A custom task runner that uses a DispatcherQueue. +class TaskRunnerWinUwp : public TaskRunner { public: - TaskRunnerTimerWinUwp(TaskRunnerTimer::Delegate* delegate); - virtual ~TaskRunnerTimerWinUwp(); + TaskRunnerWinUwp(CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired); + virtual ~TaskRunnerWinUwp(); - // |TaskRunnerTimer| - void WakeUp() override; + // |TaskRunner| + bool RunsTasksOnCurrentThread() const override; - // |TaskRunnerTimer| - bool RunsOnCurrentThread() const override; + protected: + // |TaskRunner| + void WakeUp() override; private: void OnTick(winrt::Windows::System::DispatcherQueueTimer const&, winrt::Windows::Foundation::IInspectable const&); - void ProcessTasks(); - - TaskRunnerTimer::Delegate* delegate_; + void ProcessTasksAndScheduleNext(); winrt::Windows::System::DispatcherQueue dispatcher_queue_{nullptr}; winrt::Windows::System::DispatcherQueueTimer dispatcher_queue_timer_{nullptr}; - TaskRunnerTimerWinUwp(const TaskRunnerTimerWinUwp&) = delete; - TaskRunnerTimerWinUwp& operator=(const TaskRunnerTimerWinUwp&) = delete; + TaskRunnerWinUwp(const TaskRunnerWinUwp&) = delete; + TaskRunnerWinUwp& operator=(const TaskRunnerWinUwp&) = delete; }; } // namespace flutter From e17de5a2500f470652e994f9f0c31ff4ed9b35e8 Mon Sep 17 00:00:00 2001 From: moko256 Date: Wed, 13 Oct 2021 08:34:19 +0900 Subject: [PATCH 05/10] add test for task_runner --- shell/platform/windows/BUILD.gn | 1 + .../platform/windows/task_runner_unittests.cc | 78 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 shell/platform/windows/task_runner_unittests.cc diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index caeda85ed3a12..029305ee9507d 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -227,6 +227,7 @@ executable("flutter_windows_unittests") { "sequential_id_generator_unittests.cc", "string_conversion_unittests.cc", "system_utils_unittests.cc", + "task_runner_unittests.cc", "testing/engine_modifier.h", "testing/mock_gl_functions.h", ] diff --git a/shell/platform/windows/task_runner_unittests.cc b/shell/platform/windows/task_runner_unittests.cc new file mode 100644 index 0000000000000..b3afe11a13d71 --- /dev/null +++ b/shell/platform/windows/task_runner_unittests.cc @@ -0,0 +1,78 @@ +// 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 + +#include "flutter/fml/time/time_point.h" + +#include "flutter/shell/platform/windows/task_runner.h" + +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { + +namespace { +class MockTaskRunner : public TaskRunner { + public: + MockTaskRunner(CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired) + : TaskRunner(get_current_time, on_task_expired) {} + + virtual bool RunsTasksOnCurrentThread() const override { return true; } + + void DoProcessTasks() { ProcessTasks(); } + + protected: + virtual void WakeUp() override { + // Do nothing to avoid processing tasks immediately. + } +}; + +uint64_t MockGetCurrentTime() { + return static_cast( + fml::TimePoint::Now().ToEpochDelta().ToNanoseconds()); +} +} // namespace + +TEST(TaskRunnerTest, MaybeExecuteTaskWithExactOrder) { + std::vector executed_order; + auto runner = MockTaskRunner( + MockGetCurrentTime, [&executed_order](const FlutterTask* expired_task) { + executed_order.push_back(expired_task->task); + }); + + uint64_t time_1 = MockGetCurrentTime(); + runner.PostFlutterTask(FlutterTask{nullptr, 1}, time_1); + runner.PostFlutterTask(FlutterTask{nullptr, 2}, time_1); + runner.PostTask([&executed_order]() { executed_order.push_back(3); }); + runner.PostTask([&executed_order]() { executed_order.push_back(4); }); + + runner.DoProcessTasks(); + + std::vector expect{1, 2, 3, 4}; + EXPECT_EQ(executed_order, expect); +} + +TEST(TaskRunnerTest, MaybeExecuteTaskOnlyExpired) { + std::vector executed_order; + auto runner = MockTaskRunner( + MockGetCurrentTime, [&executed_order](const FlutterTask* expired_task) { + executed_order.push_back(expired_task->task); + }); + + uint64_t time_1 = MockGetCurrentTime(); + runner.PostFlutterTask(FlutterTask{nullptr, 1}, time_1); + runner.PostFlutterTask(FlutterTask{nullptr, 2}, time_1 + 100000); + + runner.DoProcessTasks(); + + std::vector expect{1}; + EXPECT_EQ(executed_order, expect); +} + +// TEST(TaskRunnerTest, TimerAwakeAfterTheDuration) {} + +} // namespace testing +} // namespace flutter From 1ccb1a30d195ea2f0950264329807de40f825781 Mon Sep 17 00:00:00 2001 From: moko256 Date: Wed, 13 Oct 2021 08:39:55 +0900 Subject: [PATCH 06/10] remove redundant semicolons --- shell/platform/windows/task_runner_win32.cc | 4 ++-- shell/platform/windows/task_runner_winuwp.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/shell/platform/windows/task_runner_win32.cc b/shell/platform/windows/task_runner_win32.cc index 1fe72cf7e3f58..01c7179c792f5 100644 --- a/shell/platform/windows/task_runner_win32.cc +++ b/shell/platform/windows/task_runner_win32.cc @@ -27,7 +27,7 @@ TaskRunnerWin32::~TaskRunnerWin32() { bool TaskRunnerWin32::RunsTasksOnCurrentThread() const { return GetCurrentThreadId() == main_thread_id_; -}; +} std::chrono::nanoseconds TaskRunnerWin32::ProcessTasks() { return TaskRunner::ProcessTasks(); @@ -35,6 +35,6 @@ std::chrono::nanoseconds TaskRunnerWin32::ProcessTasks() { void TaskRunnerWin32::WakeUp() { task_runner_window_->WakeUp(); -}; +} } // namespace flutter diff --git a/shell/platform/windows/task_runner_winuwp.cc b/shell/platform/windows/task_runner_winuwp.cc index e74e0551a600e..5ecbcf0188d6b 100644 --- a/shell/platform/windows/task_runner_winuwp.cc +++ b/shell/platform/windows/task_runner_winuwp.cc @@ -26,11 +26,11 @@ TaskRunnerWinUwp::~TaskRunnerWinUwp() = default; bool TaskRunnerWinUwp::RunsTasksOnCurrentThread() const { return dispatcher_queue_.HasThreadAccess(); -}; +} void TaskRunnerWinUwp::WakeUp() { dispatcher_queue_.TryEnqueue([this]() { ProcessTasksAndScheduleNext(); }); -}; +} void TaskRunnerWinUwp::OnTick( winrt::Windows::System::DispatcherQueueTimer const&, From b4e4cdca044f0550e42ec3f90132a76583bab91d Mon Sep 17 00:00:00 2001 From: moko256 Date: Wed, 13 Oct 2021 23:51:47 +0900 Subject: [PATCH 07/10] meaningful names in task_runner_unittests --- .../platform/windows/task_runner_unittests.cc | 69 +++++++++++-------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/shell/platform/windows/task_runner_unittests.cc b/shell/platform/windows/task_runner_unittests.cc index b3afe11a13d71..713474d23162b 100644 --- a/shell/platform/windows/task_runner_unittests.cc +++ b/shell/platform/windows/task_runner_unittests.cc @@ -22,11 +22,12 @@ class MockTaskRunner : public TaskRunner { virtual bool RunsTasksOnCurrentThread() const override { return true; } - void DoProcessTasks() { ProcessTasks(); } + void SimulateTimerAwake() { ProcessTasks(); } protected: virtual void WakeUp() override { - // Do nothing to avoid processing tasks immediately. + // Do nothing to avoid processing tasks immediately after the tasks is + // posted. } }; @@ -37,42 +38,52 @@ uint64_t MockGetCurrentTime() { } // namespace TEST(TaskRunnerTest, MaybeExecuteTaskWithExactOrder) { - std::vector executed_order; - auto runner = MockTaskRunner( - MockGetCurrentTime, [&executed_order](const FlutterTask* expired_task) { - executed_order.push_back(expired_task->task); - }); - - uint64_t time_1 = MockGetCurrentTime(); - runner.PostFlutterTask(FlutterTask{nullptr, 1}, time_1); - runner.PostFlutterTask(FlutterTask{nullptr, 2}, time_1); - runner.PostTask([&executed_order]() { executed_order.push_back(3); }); - runner.PostTask([&executed_order]() { executed_order.push_back(4); }); - - runner.DoProcessTasks(); - - std::vector expect{1, 2, 3, 4}; - EXPECT_EQ(executed_order, expect); + std::vector executed_task_order; + auto runner = + MockTaskRunner(MockGetCurrentTime, + [&executed_task_order](const FlutterTask* expired_task) { + executed_task_order.push_back(expired_task->task); + }); + + uint64_t time_now = MockGetCurrentTime(); + + runner.PostFlutterTask(FlutterTask{nullptr, 1}, time_now); + runner.PostFlutterTask(FlutterTask{nullptr, 2}, time_now); + runner.PostTask( + [&executed_task_order]() { executed_task_order.push_back(3); }); + runner.PostTask( + [&executed_task_order]() { executed_task_order.push_back(4); }); + + runner.SimulateTimerAwake(); + + std::vector posted_task_order{1, 2, 3, 4}; + EXPECT_EQ(executed_task_order, posted_task_order); } TEST(TaskRunnerTest, MaybeExecuteTaskOnlyExpired) { - std::vector executed_order; + std::set executed_task; auto runner = MockTaskRunner( - MockGetCurrentTime, [&executed_order](const FlutterTask* expired_task) { - executed_order.push_back(expired_task->task); + MockGetCurrentTime, [&executed_task](const FlutterTask* expired_task) { + executed_task.insert(expired_task->task); }); - uint64_t time_1 = MockGetCurrentTime(); - runner.PostFlutterTask(FlutterTask{nullptr, 1}, time_1); - runner.PostFlutterTask(FlutterTask{nullptr, 2}, time_1 + 100000); + uint64_t time_now = MockGetCurrentTime(); - runner.DoProcessTasks(); + uint64_t task_expired_before_now = 1; + uint64_t time_before_now = time_now - 10000; + runner.PostFlutterTask(FlutterTask{nullptr, task_expired_before_now}, + time_before_now); - std::vector expect{1}; - EXPECT_EQ(executed_order, expect); -} + uint64_t task_expired_after_now = 2; + uint64_t time_after_now = time_now + 10000; + runner.PostFlutterTask(FlutterTask{nullptr, task_expired_after_now}, + time_after_now); -// TEST(TaskRunnerTest, TimerAwakeAfterTheDuration) {} + runner.SimulateTimerAwake(); + + std::set only_task_expired_before_now{task_expired_before_now}; + EXPECT_EQ(executed_task, only_task_expired_before_now); +} } // namespace testing } // namespace flutter From dad8d7502f6d3700a449f7fad255c4c10132e474 Mon Sep 17 00:00:00 2001 From: moko256 Date: Wed, 13 Oct 2021 23:56:29 +0900 Subject: [PATCH 08/10] apply filename for the name for include guard in task_runner_winuwp.h --- shell/platform/windows/task_runner_winuwp.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shell/platform/windows/task_runner_winuwp.h b/shell/platform/windows/task_runner_winuwp.h index b1d7e524a2f80..978db49fec661 100644 --- a/shell/platform/windows/task_runner_winuwp.h +++ b/shell/platform/windows/task_runner_winuwp.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_WINRT_TASK_RUNNER_H_ -#define FLUTTER_SHELL_PLATFORM_WINDOWS_WINRT_TASK_RUNNER_H_ +#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_WINUWP_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_WINUWP_H_ #include #include @@ -42,4 +42,4 @@ class TaskRunnerWinUwp : public TaskRunner { } // namespace flutter -#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_WINRT_TASK_RUNNER_H_ +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_WINUWP_H_ From 3cd8493c2613ffa30fcfaad14463457a5cd217b1 Mon Sep 17 00:00:00 2001 From: moko256 Date: Thu, 14 Oct 2021 06:46:41 +0900 Subject: [PATCH 09/10] convert CRLF to LF in task_runner_winuwp --- shell/platform/windows/task_runner_winuwp.cc | 106 +++++++++---------- shell/platform/windows/task_runner_winuwp.h | 90 ++++++++-------- 2 files changed, 98 insertions(+), 98 deletions(-) diff --git a/shell/platform/windows/task_runner_winuwp.cc b/shell/platform/windows/task_runner_winuwp.cc index 5ecbcf0188d6b..8bba42ed741bf 100644 --- a/shell/platform/windows/task_runner_winuwp.cc +++ b/shell/platform/windows/task_runner_winuwp.cc @@ -1,53 +1,53 @@ -// 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/windows/task_runner_winuwp.h" - -namespace flutter { - -// static -std::unique_ptr TaskRunner::Create( - CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired) { - return std::make_unique(get_current_time, on_task_expired); -} - -TaskRunnerWinUwp::TaskRunnerWinUwp(CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired) - : TaskRunner(get_current_time, on_task_expired) { - dispatcher_queue_ = - winrt::Windows::System::DispatcherQueue::GetForCurrentThread(); - dispatcher_queue_timer_ = dispatcher_queue_.CreateTimer(); - dispatcher_queue_timer_.Tick({this, &TaskRunnerWinUwp::OnTick}); -} - -TaskRunnerWinUwp::~TaskRunnerWinUwp() = default; - -bool TaskRunnerWinUwp::RunsTasksOnCurrentThread() const { - return dispatcher_queue_.HasThreadAccess(); -} - -void TaskRunnerWinUwp::WakeUp() { - dispatcher_queue_.TryEnqueue([this]() { ProcessTasksAndScheduleNext(); }); -} - -void TaskRunnerWinUwp::OnTick( - winrt::Windows::System::DispatcherQueueTimer const&, - winrt::Windows::Foundation::IInspectable const&) { - ProcessTasks(); -} - -void TaskRunnerWinUwp::ProcessTasksAndScheduleNext() { - auto next = ProcessTasks(); - - if (next == std::chrono::nanoseconds::max()) { - dispatcher_queue_timer_.Stop(); - } else { - dispatcher_queue_timer_.Interval( - std::chrono::duration_cast(next)); - dispatcher_queue_timer_.Start(); - } -} - -} // namespace flutter +// 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/windows/task_runner_winuwp.h" + +namespace flutter { + +// static +std::unique_ptr TaskRunner::Create( + CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired) { + return std::make_unique(get_current_time, on_task_expired); +} + +TaskRunnerWinUwp::TaskRunnerWinUwp(CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired) + : TaskRunner(get_current_time, on_task_expired) { + dispatcher_queue_ = + winrt::Windows::System::DispatcherQueue::GetForCurrentThread(); + dispatcher_queue_timer_ = dispatcher_queue_.CreateTimer(); + dispatcher_queue_timer_.Tick({this, &TaskRunnerWinUwp::OnTick}); +} + +TaskRunnerWinUwp::~TaskRunnerWinUwp() = default; + +bool TaskRunnerWinUwp::RunsTasksOnCurrentThread() const { + return dispatcher_queue_.HasThreadAccess(); +} + +void TaskRunnerWinUwp::WakeUp() { + dispatcher_queue_.TryEnqueue([this]() { ProcessTasksAndScheduleNext(); }); +} + +void TaskRunnerWinUwp::OnTick( + winrt::Windows::System::DispatcherQueueTimer const&, + winrt::Windows::Foundation::IInspectable const&) { + ProcessTasks(); +} + +void TaskRunnerWinUwp::ProcessTasksAndScheduleNext() { + auto next = ProcessTasks(); + + if (next == std::chrono::nanoseconds::max()) { + dispatcher_queue_timer_.Stop(); + } else { + dispatcher_queue_timer_.Interval( + std::chrono::duration_cast(next)); + dispatcher_queue_timer_.Start(); + } +} + +} // namespace flutter diff --git a/shell/platform/windows/task_runner_winuwp.h b/shell/platform/windows/task_runner_winuwp.h index 978db49fec661..d92ce80a46230 100644 --- a/shell/platform/windows/task_runner_winuwp.h +++ b/shell/platform/windows/task_runner_winuwp.h @@ -1,45 +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_WINDOWS_TASK_RUNNER_WINUWP_H_ -#define FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_WINUWP_H_ - -#include -#include - -#include "flutter/shell/platform/embedder/embedder.h" -#include "flutter/shell/platform/windows/task_runner.h" - -namespace flutter { - -// A custom task runner that uses a DispatcherQueue. -class TaskRunnerWinUwp : public TaskRunner { - public: - TaskRunnerWinUwp(CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired); - virtual ~TaskRunnerWinUwp(); - - // |TaskRunner| - bool RunsTasksOnCurrentThread() const override; - - protected: - // |TaskRunner| - void WakeUp() override; - - private: - void OnTick(winrt::Windows::System::DispatcherQueueTimer const&, - winrt::Windows::Foundation::IInspectable const&); - - void ProcessTasksAndScheduleNext(); - - winrt::Windows::System::DispatcherQueue dispatcher_queue_{nullptr}; - winrt::Windows::System::DispatcherQueueTimer dispatcher_queue_timer_{nullptr}; - - TaskRunnerWinUwp(const TaskRunnerWinUwp&) = delete; - TaskRunnerWinUwp& operator=(const TaskRunnerWinUwp&) = delete; -}; - -} // namespace flutter - -#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_WINUWP_H_ +// 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_WINDOWS_TASK_RUNNER_WINUWP_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_WINUWP_H_ + +#include +#include + +#include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/windows/task_runner.h" + +namespace flutter { + +// A custom task runner that uses a DispatcherQueue. +class TaskRunnerWinUwp : public TaskRunner { + public: + TaskRunnerWinUwp(CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired); + virtual ~TaskRunnerWinUwp(); + + // |TaskRunner| + bool RunsTasksOnCurrentThread() const override; + + protected: + // |TaskRunner| + void WakeUp() override; + + private: + void OnTick(winrt::Windows::System::DispatcherQueueTimer const&, + winrt::Windows::Foundation::IInspectable const&); + + void ProcessTasksAndScheduleNext(); + + winrt::Windows::System::DispatcherQueue dispatcher_queue_{nullptr}; + winrt::Windows::System::DispatcherQueueTimer dispatcher_queue_timer_{nullptr}; + + TaskRunnerWinUwp(const TaskRunnerWinUwp&) = delete; + TaskRunnerWinUwp& operator=(const TaskRunnerWinUwp&) = delete; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_WINUWP_H_ From 665b8f76047a8452acf545b638a4fd7ffd7ab656 Mon Sep 17 00:00:00 2001 From: moko256 Date: Sat, 16 Oct 2021 05:08:05 +0900 Subject: [PATCH 10/10] add files in task_runner to licenses --- ci/licenses_golden/licenses_flutter | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 97f2e2fa5c669..614bdc4125067 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1753,7 +1753,9 @@ FILE: ../../../flutter/shell/platform/windows/system_utils.h FILE: ../../../flutter/shell/platform/windows/system_utils_unittests.cc FILE: ../../../flutter/shell/platform/windows/system_utils_win32.cc FILE: ../../../flutter/shell/platform/windows/system_utils_winuwp.cc +FILE: ../../../flutter/shell/platform/windows/task_runner.cc FILE: ../../../flutter/shell/platform/windows/task_runner.h +FILE: ../../../flutter/shell/platform/windows/task_runner_unittests.cc FILE: ../../../flutter/shell/platform/windows/task_runner_win32.cc FILE: ../../../flutter/shell/platform/windows/task_runner_win32.h FILE: ../../../flutter/shell/platform/windows/task_runner_win32_window.cc