1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "flutter/shell/platform/glfw/event_loop.h"
6
7#include <atomic>
8#include <utility>
9
10namespace flutter {
11
12EventLoop::EventLoop(std::thread::id main_thread_id,
13 const TaskExpiredCallback& on_task_expired)
14 : main_thread_id_(main_thread_id), on_task_expired_(on_task_expired) {}
15
16EventLoop::~EventLoop() = default;
17
18bool EventLoop::RunsTasksOnCurrentThread() const {
19 return std::this_thread::get_id() == main_thread_id_;
20}
21
22void EventLoop::WaitForEvents(std::chrono::nanoseconds max_wait) {
23 const auto now = TaskTimePoint::clock::now();
24 std::vector<FlutterTask> expired_tasks;
25
26 // Process expired tasks.
27 {
28 std::lock_guard<std::mutex> lock(task_queue_mutex_);
29 while (!task_queue_.empty()) {
30 const auto& top = task_queue_.top();
31 // If this task (and all tasks after this) has not yet expired, there is
32 // nothing more to do. Quit iterating.
33 if (top.fire_time > now) {
34 break;
35 }
36
37 // Make a record of the expired task. Do NOT service the task here
38 // because we are still holding onto the task queue mutex. We don't want
39 // other threads to block on posting tasks onto this thread till we are
40 // done processing expired tasks.
41 expired_tasks.push_back(x: task_queue_.top().task);
42
43 // Remove the tasks from the delayed tasks queue.
44 task_queue_.pop();
45 }
46 }
47
48 // Fire expired tasks.
49 {
50 // Flushing tasks here without holing onto the task queue mutex.
51 for (const auto& task : expired_tasks) {
52 on_task_expired_(&task);
53 }
54 }
55
56 // Sleep till the next task needs to be processed. If a new task comes
57 // along, the wait will be resolved early because PostTask calls Wake().
58 {
59 TaskTimePoint next_wake;
60 {
61 std::lock_guard<std::mutex> lock(task_queue_mutex_);
62 TaskTimePoint max_wake_timepoint =
63 max_wait == std::chrono::nanoseconds::max() ? TaskTimePoint::max()
64 : now + max_wait;
65 TaskTimePoint next_event_timepoint = task_queue_.empty()
66 ? TaskTimePoint::max()
67 : task_queue_.top().fire_time;
68 next_wake = std::min(a: max_wake_timepoint, b: next_event_timepoint);
69 }
70 WaitUntil(time: next_wake);
71 }
72}
73
74EventLoop::TaskTimePoint EventLoop::TimePointFromFlutterTime(
75 uint64_t flutter_target_time_nanos) {
76 const auto now = TaskTimePoint::clock::now();
77 const int64_t flutter_duration =
78 flutter_target_time_nanos - FlutterEngineGetCurrentTime();
79 return now + std::chrono::nanoseconds(flutter_duration);
80}
81
82void EventLoop::PostTask(FlutterTask flutter_task,
83 uint64_t flutter_target_time_nanos) {
84 static std::atomic_uint64_t sGlobalTaskOrder(0);
85
86 Task task;
87 task.order = ++sGlobalTaskOrder;
88 task.fire_time = TimePointFromFlutterTime(flutter_target_time_nanos);
89 task.task = flutter_task;
90
91 {
92 std::lock_guard<std::mutex> lock(task_queue_mutex_);
93 task_queue_.push(v: task);
94
95 // Make sure the queue mutex is unlocked before waking up the loop. In case
96 // the wake causes this thread to be descheduled for the primary thread to
97 // process tasks, the acquisition of the lock on that thread while holding
98 // the lock here momentarily till the end of the scope is a pessimization.
99 }
100 Wake();
101}
102
103} // namespace flutter
104

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com

source code of flutter_engine/flutter/shell/platform/glfw/event_loop.cc