| 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 };
22
23 typedef struct _FlTaskRunnerTask {
24 // absolute time of task (based on g_get_monotonic_time).
25 gint64 task_time_micros;
26
27 // flutter task to execute if schedule through
28 // fl_task_runner_post_flutter_task.
29 FlutterTask task;
30 } FlTaskRunnerTask;
31
32 G_DEFINE_TYPE(FlTaskRunner, fl_task_runner, G_TYPE_OBJECT)
33
34 // Removes expired tasks from the task queue and executes them.
35 // The execution is performed with mutex unlocked.
36 static void fl_task_runner_process_expired_tasks_locked(FlTaskRunner* self) {
37 GList* expired_tasks = nullptr;
38
39 gint64 current_time = g_get_monotonic_time();
40
41 GList* l = self->pending_tasks;
42 while (l != nullptr) {
43 FlTaskRunnerTask* task = static_cast<FlTaskRunnerTask*>(l->data);
44 if (task->task_time_micros <= current_time) {
45 GList* link = l;
46 l = l->next;
47 self->pending_tasks = g_list_remove_link(self->pending_tasks, link);
48 expired_tasks = g_list_concat(expired_tasks, link);
49 } else {
50 l = l->next;
51 }
52 }
53
54 g_mutex_unlock(&self->mutex);
55
56 g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
57 if (engine != nullptr) {
58 l = expired_tasks;
59 while (l != nullptr) {
60 FlTaskRunnerTask* task = static_cast<FlTaskRunnerTask*>(l->data);
61 fl_engine_execute_task(engine, &task->task);
62 l = l->next;
63 }
64 }
65
66 g_list_free_full(expired_tasks, g_free);
67
68 g_mutex_lock(&self->mutex);
69 }
70
71 static void fl_task_runner_tasks_did_change_locked(FlTaskRunner* self);
72
73 // Invoked from a timeout source. Removes and executes expired tasks
74 // and reschedules timeout if needed.
75 static gboolean fl_task_runner_on_expired_timeout(gpointer data) {
76 FlTaskRunner* self = FL_TASK_RUNNER(data);
77
78 g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->mutex);
79 (void)locker; // unused variable
80
81 g_object_ref(self);
82
83 self->timeout_source_id = 0;
84 fl_task_runner_process_expired_tasks_locked(self);
85
86 // reschedule timeout
87 fl_task_runner_tasks_did_change_locked(self);
88
89 g_object_unref(self);
90
91 return FALSE;
92 }
93
94 // Returns the absolute time of next expired task (in microseconds, based on
95 // g_get_monotonic_time). If no task is scheduled returns G_MAXINT64.
96 static gint64 fl_task_runner_next_task_expiration_time_locked(
97 FlTaskRunner* self) {
98 gint64 min_time = G_MAXINT64;
99 GList* l = self->pending_tasks;
100 while (l != nullptr) {
101 FlTaskRunnerTask* task = static_cast<FlTaskRunnerTask*>(l->data);
102 min_time = MIN(min_time, task->task_time_micros);
103 l = l->next;
104 }
105 return min_time;
106 }
107
108 static void fl_task_runner_tasks_did_change_locked(FlTaskRunner* self) {
109 // Reschedule timeout
110 if (self->timeout_source_id != 0) {
111 g_source_remove(self->timeout_source_id);
112 self->timeout_source_id = 0;
113 }
114 gint64 min_time = fl_task_runner_next_task_expiration_time_locked(self);
115 if (min_time != G_MAXINT64) {
116 gint64 remaining = MAX(min_time - g_get_monotonic_time(), 0);
117 self->timeout_source_id =
118 g_timeout_add(remaining / kMillisecondsPerMicrosecond + 1,
119 fl_task_runner_on_expired_timeout, self);
120 }
121 }
122
123 void fl_task_runner_dispose(GObject* object) {
124 FlTaskRunner* self = FL_TASK_RUNNER(object);
125
126 g_weak_ref_clear(&self->engine);
127 g_mutex_clear(&self->mutex);
128 g_cond_clear(&self->cond);
129
130 g_list_free_full(self->pending_tasks, g_free);
131 if (self->timeout_source_id != 0) {
132 g_source_remove(self->timeout_source_id);
133 }
134
135 G_OBJECT_CLASS(fl_task_runner_parent_class)->dispose(object);
136 }
137
138 static void fl_task_runner_class_init(FlTaskRunnerClass* klass) {
139 G_OBJECT_CLASS(klass)->dispose = fl_task_runner_dispose;
140 }
141
142 static void fl_task_runner_init(FlTaskRunner* self) {
143 g_mutex_init(&self->mutex);
144 g_cond_init(&self->cond);
145 }
146
147 FlTaskRunner* fl_task_runner_new(FlEngine* engine) {
148 FlTaskRunner* self =
149 FL_TASK_RUNNER(g_object_new(fl_task_runner_get_type(), nullptr));
150 g_weak_ref_init(&self->engine, G_OBJECT(engine));
151 return self;
152 }
153
154 void fl_task_runner_post_flutter_task(FlTaskRunner* self,
155 FlutterTask task,
156 uint64_t target_time_nanos) {
157 g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->mutex);
158 (void)locker; // unused variable
159
160 FlTaskRunnerTask* runner_task = g_new0(FlTaskRunnerTask, 1);
161 runner_task->task = task;
162 runner_task->task_time_micros =
163 target_time_nanos / kMicrosecondsPerNanosecond;
164
165 self->pending_tasks = g_list_append(self->pending_tasks, runner_task);
166 fl_task_runner_tasks_did_change_locked(self);
167
168 // Tasks changed, so wake up anything blocking in fl_task_runner_wait.
169 g_cond_signal(&self->cond);
170 }
171
172 void fl_task_runner_wait(FlTaskRunner* self) {
173 g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->mutex);
174 (void)locker; // unused variable
175
176 g_cond_wait_until(&self->cond, &self->mutex,
177 fl_task_runner_next_task_expiration_time_locked(self));
178 fl_task_runner_process_expired_tasks_locked(self);
179 fl_task_runner_tasks_did_change_locked(self);
180 }
181
182 void fl_task_runner_stop_wait(FlTaskRunner* self) {
183 g_cond_signal(&self->cond);
184 }
g_autoptr
g_autoptr(FlEngine) engine
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:1462
fl_engine_private.h
fl_task_runner_wait
void fl_task_runner_wait(FlTaskRunner *self)
Definition: fl_task_runner.cc:172
fl_task_runner_stop_wait
void fl_task_runner_stop_wait(FlTaskRunner *self)
Definition: fl_task_runner.cc:182
fl_task_runner_dispose
void fl_task_runner_dispose(GObject *object)
Definition: fl_task_runner.cc:123
fl_task_runner_process_expired_tasks_locked
static void fl_task_runner_process_expired_tasks_locked(FlTaskRunner *self)
Definition: fl_task_runner.cc:36
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:154
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:96
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:138
fl_task_runner_tasks_did_change_locked
static void fl_task_runner_tasks_did_change_locked(FlTaskRunner *self)
Definition: fl_task_runner.cc:108
fl_task_runner_on_expired_timeout
static gboolean fl_task_runner_on_expired_timeout(gpointer data)
Definition: fl_task_runner.cc:75
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:147
fl_task_runner_init
static void fl_task_runner_init(FlTaskRunner *self)
Definition: fl_task_runner.cc:142
fl_task_runner.h
_FlTaskRunner
Definition: fl_task_runner.cc:11
_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:23
_FlTaskRunnerTask::task
FlutterTask task
Definition: fl_task_runner.cc:29
_FlTaskRunnerTask::task_time_micros
gint64 task_time_micros
Definition: fl_task_runner.cc:25