| Flutter Linux Embedder |

fl_task_runner.cc
Go to the documentation of this file.
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/linux/fl_task_runner.h"
6 #include "flutter/shell/platform/linux/fl_engine_private.h"
7
8 static constexpr int kMicrosecondsPerNanosecond = 1000;
9 static constexpr int kMillisecondsPerMicrosecond = 1000;
10
11 struct _FlTaskRunner {
12 GObject parent_instance;
13
14 GWeakRef engine;
15
16 GMutex mutex;
17 GCond cond;
18
19 guint timeout_source_id;
20 GList /*<FlTaskRunnerTask>*/* pending_tasks;
21 gboolean blocking_main_thread;
22 };
23
24 typedef struct _FlTaskRunnerTask {
25 // absolute time of task (based on g_get_monotonic_time).
26 gint64 task_time_micros;
27
28 // flutter task to execute if schedule through
29 // fl_task_runner_post_flutter_task.
30 FlutterTask task;
31
32 // callback to execute if scheduled through fl_task_runner_post_callback.
33 void (*callback)(gpointer data);
34
35 // data for the callback.
36 gpointer callback_data;
37 } FlTaskRunnerTask;
38
39 G_DEFINE_TYPE(FlTaskRunner, fl_task_runner, G_TYPE_OBJECT)
40
41 // Removes expired tasks from the task queue and executes them.
42 // The execution is performed with mutex unlocked.
43 static void fl_task_runner_process_expired_tasks_locked(FlTaskRunner* self) {
44 GList* expired_tasks = nullptr;
45
46 gint64 current_time = g_get_monotonic_time();
47
48 GList* l = self->pending_tasks;
49 while (l != nullptr) {
50 FlTaskRunnerTask* task = static_cast<FlTaskRunnerTask*>(l->data);
51 if (task->task_time_micros <= current_time) {
52 GList* link = l;
53 l = l->next;
54 self->pending_tasks = g_list_remove_link(self->pending_tasks, link);
55 expired_tasks = g_list_concat(expired_tasks, link);
56 } else {
57 l = l->next;
58 }
59 }
60
61 g_mutex_unlock(&self->mutex);
62
63 g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
64 if (engine != nullptr) {
65 l = expired_tasks;
66 while (l != nullptr) {
67 FlTaskRunnerTask* task = static_cast<FlTaskRunnerTask*>(l->data);
68 if (task->callback != nullptr) {
69 task->callback(task->callback_data);
70 } else {
71 fl_engine_execute_task(engine, &task->task);
72 }
73 l = l->next;
74 }
75 }
76
77 g_list_free_full(expired_tasks, g_free);
78
79 g_mutex_lock(&self->mutex);
80 }
81
82 static void fl_task_runner_tasks_did_change_locked(FlTaskRunner* self);
83
84 // Invoked from a timeout source. Removes and executes expired tasks
85 // and reschedules timeout if needed.
86 static gboolean fl_task_runner_on_expired_timeout(gpointer data) {
87 FlTaskRunner* self = FL_TASK_RUNNER(data);
88
89 g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->mutex);
90 (void)locker; // unused variable
91
92 g_object_ref(self);
93
94 self->timeout_source_id = 0;
95 fl_task_runner_process_expired_tasks_locked(self);
96
97 // reschedule timeout
98 fl_task_runner_tasks_did_change_locked(self);
99
100 g_object_unref(self);
101
102 return FALSE;
103 }
104
105 // Returns the absolute time of next expired task (in microseconds, based on
106 // g_get_monotonic_time). If no task is scheduled returns G_MAXINT64.
107 static gint64 fl_task_runner_next_task_expiration_time_locked(
108 FlTaskRunner* self) {
109 gint64 min_time = G_MAXINT64;
110 GList* l = self->pending_tasks;
111 while (l != nullptr) {
112 FlTaskRunnerTask* task = static_cast<FlTaskRunnerTask*>(l->data);
113 min_time = MIN(min_time, task->task_time_micros);
114 l = l->next;
115 }
116 return min_time;
117 }
118
119 static void fl_task_runner_tasks_did_change_locked(FlTaskRunner* self) {
120 if (self->blocking_main_thread) {
121 // Wake up blocked thread
122 g_cond_signal(&self->cond);
123 } else {
124 // Reschedule timeout
125 if (self->timeout_source_id != 0) {
126 g_source_remove(self->timeout_source_id);
127 self->timeout_source_id = 0;
128 }
129 gint64 min_time = fl_task_runner_next_task_expiration_time_locked(self);
130 if (min_time != G_MAXINT64) {
131 gint64 remaining = MAX(min_time - g_get_monotonic_time(), 0);
132 self->timeout_source_id =
133 g_timeout_add(remaining / kMillisecondsPerMicrosecond + 1,
134 fl_task_runner_on_expired_timeout, self);
135 }
136 }
137 }
138
139 void fl_task_runner_dispose(GObject* object) {
140 FlTaskRunner* self = FL_TASK_RUNNER(object);
141
142 // this should never happen because the task runner is retained while blocking
143 // main thread
144 g_assert(!self->blocking_main_thread);
145
146 g_weak_ref_clear(&self->engine);
147 g_mutex_clear(&self->mutex);
148 g_cond_clear(&self->cond);
149
150 g_list_free_full(self->pending_tasks, g_free);
151 if (self->timeout_source_id != 0) {
152 g_source_remove(self->timeout_source_id);
153 }
154
155 G_OBJECT_CLASS(fl_task_runner_parent_class)->dispose(object);
156 }
157
158 static void fl_task_runner_class_init(FlTaskRunnerClass* klass) {
159 G_OBJECT_CLASS(klass)->dispose = fl_task_runner_dispose;
160 }
161
162 static void fl_task_runner_init(FlTaskRunner* self) {
163 g_mutex_init(&self->mutex);
164 g_cond_init(&self->cond);
165 }
166
167 FlTaskRunner* fl_task_runner_new(FlEngine* engine) {
168 FlTaskRunner* self =
169 FL_TASK_RUNNER(g_object_new(fl_task_runner_get_type(), nullptr));
170 g_weak_ref_init(&self->engine, G_OBJECT(engine));
171 return self;
172 }
173
174 void fl_task_runner_post_flutter_task(FlTaskRunner* self,
175 FlutterTask task,
176 uint64_t target_time_nanos) {
177 g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->mutex);
178 (void)locker; // unused variable
179
180 FlTaskRunnerTask* runner_task = g_new0(FlTaskRunnerTask, 1);
181 runner_task->task = task;
182 runner_task->task_time_micros =
183 target_time_nanos / kMicrosecondsPerNanosecond;
184
185 self->pending_tasks = g_list_append(self->pending_tasks, runner_task);
186 fl_task_runner_tasks_did_change_locked(self);
187 }
188
189 void fl_task_runner_post_callback(FlTaskRunner* self,
190 void (*callback)(gpointer data),
191 gpointer data) {
192 g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->mutex);
193 (void)locker; // unused variable
194
195 FlTaskRunnerTask* runner_task = g_new0(FlTaskRunnerTask, 1);
196 runner_task->callback = callback;
197 runner_task->callback_data = data;
198
199 self->pending_tasks = g_list_append(self->pending_tasks, runner_task);
200 fl_task_runner_tasks_did_change_locked(self);
201 }
202
203 void fl_task_runner_block_main_thread(FlTaskRunner* self) {
204 g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->mutex);
205 (void)locker; // unused variable
206
207 g_return_if_fail(self->blocking_main_thread == FALSE);
208
209 g_object_ref(self);
210
211 self->blocking_main_thread = true;
212 while (self->blocking_main_thread) {
213 g_cond_wait_until(&self->cond, &self->mutex,
214 fl_task_runner_next_task_expiration_time_locked(self));
215 fl_task_runner_process_expired_tasks_locked(self);
216 }
217
218 // Tasks might have changed in the meanwhile, reschedule timeout
219 fl_task_runner_tasks_did_change_locked(self);
220
221 g_object_unref(self);
222 }
223
224 void fl_task_runner_release_main_thread(FlTaskRunner* self) {
225 g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->mutex);
226 (void)locker; // unused variable
227
228 g_return_if_fail(self->blocking_main_thread == TRUE);
229
230 self->blocking_main_thread = FALSE;
231 g_cond_signal(&self->cond);
232 }
G_DEFINE_TYPE
G_DEFINE_TYPE(FlBasicMessageChannelResponseHandle, fl_basic_message_channel_response_handle, G_TYPE_OBJECT) static void fl_basic_message_channel_response_handle_dispose(GObject *object)
Definition: fl_basic_message_channel.cc:37
fl_engine_execute_task
void fl_engine_execute_task(FlEngine *self, FlutterTask *task)
Definition: fl_engine.cc:1424
fl_engine_private.h
TRUE
return TRUE
Definition: fl_pixel_buffer_texture_test.cc:53
fl_task_runner_dispose
void fl_task_runner_dispose(GObject *object)
Definition: fl_task_runner.cc:139
fl_task_runner_post_callback
void fl_task_runner_post_callback(FlTaskRunner *self, void(*callback)(gpointer data), gpointer data)
Definition: fl_task_runner.cc:189
fl_task_runner_process_expired_tasks_locked
static void fl_task_runner_process_expired_tasks_locked(FlTaskRunner *self)
Definition: fl_task_runner.cc:43
fl_task_runner_post_flutter_task
void fl_task_runner_post_flutter_task(FlTaskRunner *self, FlutterTask task, uint64_t target_time_nanos)
Definition: fl_task_runner.cc:174
FlTaskRunnerTask
struct _FlTaskRunnerTask FlTaskRunnerTask
fl_task_runner_next_task_expiration_time_locked
static gint64 fl_task_runner_next_task_expiration_time_locked(FlTaskRunner *self)
Definition: fl_task_runner.cc:107
fl_task_runner_release_main_thread
void fl_task_runner_release_main_thread(FlTaskRunner *self)
Definition: fl_task_runner.cc:224
kMillisecondsPerMicrosecond
static constexpr int kMillisecondsPerMicrosecond
Definition: fl_task_runner.cc:9
fl_task_runner_class_init
static void fl_task_runner_class_init(FlTaskRunnerClass *klass)
Definition: fl_task_runner.cc:158
fl_task_runner_tasks_did_change_locked
static void fl_task_runner_tasks_did_change_locked(FlTaskRunner *self)
Definition: fl_task_runner.cc:119
fl_task_runner_block_main_thread
void fl_task_runner_block_main_thread(FlTaskRunner *self)
Definition: fl_task_runner.cc:203
fl_task_runner_on_expired_timeout
static gboolean fl_task_runner_on_expired_timeout(gpointer data)
Definition: fl_task_runner.cc:86
kMicrosecondsPerNanosecond
static constexpr int kMicrosecondsPerNanosecond
Definition: fl_task_runner.cc:8
fl_task_runner_new
FlTaskRunner * fl_task_runner_new(FlEngine *engine)
Definition: fl_task_runner.cc:167
fl_task_runner_init
static void fl_task_runner_init(FlTaskRunner *self)
Definition: fl_task_runner.cc:162
fl_task_runner.h
_FlTaskRunner
Definition: fl_task_runner.cc:11
_FlTaskRunner::blocking_main_thread
gboolean blocking_main_thread
Definition: fl_task_runner.cc:21
_FlTaskRunner::timeout_source_id
guint timeout_source_id
Definition: fl_task_runner.cc:19
_FlTaskRunner::pending_tasks
GList * pending_tasks
Definition: fl_task_runner.cc:20
_FlTaskRunner::engine
GWeakRef engine
Definition: fl_task_runner.cc:14
_FlTaskRunner::mutex
GMutex mutex
Definition: fl_task_runner.cc:16
_FlTaskRunner::parent_instance
GObject parent_instance
Definition: fl_task_runner.cc:12
_FlTaskRunner::cond
GCond cond
Definition: fl_task_runner.cc:17
_FlTaskRunnerTask
Definition: fl_task_runner.cc:24
_FlTaskRunnerTask::task
FlutterTask task
Definition: fl_task_runner.cc:30
_FlTaskRunnerTask::callback_data
gpointer callback_data
Definition: fl_task_runner.cc:36
_FlTaskRunnerTask::task_time_micros
gint64 task_time_micros
Definition: fl_task_runner.cc:26
_FlTaskRunnerTask::callback
void(* callback)(gpointer data)
Definition: fl_task_runner.cc:33