Flutter Linux Embedder
fl_task_runner.cc File Reference

Go to the source code of this file.

Classes

struct  _FlTaskRunner
 
struct  _FlTaskRunnerTask
 

Typedefs

typedef struct _FlTaskRunnerTask FlTaskRunnerTask
 

Functions

static void fl_task_runner_process_expired_tasks_locked (FlTaskRunner *self)
 
static void fl_task_runner_tasks_did_change_locked (FlTaskRunner *self)
 
static gboolean fl_task_runner_on_expired_timeout (gpointer data)
 
static gint64 fl_task_runner_next_task_expiration_time_locked (FlTaskRunner *self)
 
void fl_task_runner_dispose (GObject *object)
 
static void fl_task_runner_class_init (FlTaskRunnerClass *klass)
 
static void fl_task_runner_init (FlTaskRunner *self)
 
FlTaskRunner * fl_task_runner_new (FlEngine *engine)
 
void fl_task_runner_post_flutter_task (FlTaskRunner *self, FlutterTask task, uint64_t target_time_nanos)
 
void fl_task_runner_post_callback (FlTaskRunner *self, void(*callback)(gpointer data), gpointer data)
 
void fl_task_runner_block_main_thread (FlTaskRunner *self)
 
void fl_task_runner_release_main_thread (FlTaskRunner *self)
 

Variables

static constexpr int kMicrosecondsPerNanosecond = 1000
 
static constexpr int kMillisecondsPerMicrosecond = 1000
 

Typedef Documentation

◆ FlTaskRunnerTask

Function Documentation

◆ fl_task_runner_block_main_thread()

void fl_task_runner_block_main_thread ( 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.

Definition at line 203 of file fl_task_runner.cc.

203  {
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,
216  }
217 
218  // Tasks might have changed in the meanwhile, reschedule timeout
220 
221  g_object_unref(self);
222 }
static void fl_task_runner_process_expired_tasks_locked(FlTaskRunner *self)
static gint64 fl_task_runner_next_task_expiration_time_locked(FlTaskRunner *self)
static void fl_task_runner_tasks_did_change_locked(FlTaskRunner *self)

References fl_task_runner_next_task_expiration_time_locked(), fl_task_runner_process_expired_tasks_locked(), and fl_task_runner_tasks_did_change_locked().

Referenced by fl_compositor_opengl_wait_for_frame().

◆ fl_task_runner_class_init()

static void fl_task_runner_class_init ( FlTaskRunnerClass *  klass)
static

Definition at line 158 of file fl_task_runner.cc.

158  {
159  G_OBJECT_CLASS(klass)->dispose = fl_task_runner_dispose;
160 }
void fl_task_runner_dispose(GObject *object)

References fl_task_runner_dispose().

◆ fl_task_runner_dispose()

void fl_task_runner_dispose ( GObject *  object)

Definition at line 139 of file fl_task_runner.cc.

139  {
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 }

Referenced by fl_task_runner_class_init().

◆ fl_task_runner_init()

static void fl_task_runner_init ( FlTaskRunner *  self)
static

Definition at line 162 of file fl_task_runner.cc.

162  {
163  g_mutex_init(&self->mutex);
164  g_cond_init(&self->cond);
165 }

◆ fl_task_runner_new()

FlTaskRunner* fl_task_runner_new ( FlEngine *  engine)

fl_task_runner_new: @engine: the #FlEngine owning the task runner.

Creates new task runner instance.

Returns: an #FlTaskRunner.

Definition at line 167 of file fl_task_runner.cc.

167  {
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 }

Referenced by fl_engine_init().

◆ fl_task_runner_next_task_expiration_time_locked()

static gint64 fl_task_runner_next_task_expiration_time_locked ( FlTaskRunner *  self)
static

Definition at line 107 of file fl_task_runner.cc.

108  {
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 }

References _FlTaskRunnerTask::task_time_micros.

Referenced by fl_task_runner_block_main_thread(), and fl_task_runner_tasks_did_change_locked().

◆ fl_task_runner_on_expired_timeout()

static gboolean fl_task_runner_on_expired_timeout ( gpointer  data)
static

Definition at line 86 of file fl_task_runner.cc.

86  {
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;
96 
97  // reschedule timeout
99 
100  g_object_unref(self);
101 
102  return FALSE;
103 }

References fl_task_runner_process_expired_tasks_locked(), and fl_task_runner_tasks_did_change_locked().

Referenced by fl_task_runner_tasks_did_change_locked().

◆ fl_task_runner_post_callback()

void fl_task_runner_post_callback ( FlTaskRunner *  task_runner,
void(*)(gpointer data)  callback,
gpointer  data 
)

fl_task_runner_post_callback: @task_runner: an #FlTaskRunner. @callback: callback to be scheduled @data: data to be passed to the callback

Schedules arbitrary callback to be executed on main thread. The callback will be executed in next run loop turn. This function is thread safe and may be called from any thread.

Definition at line 189 of file fl_task_runner.cc.

191  {
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);
201 }
void(* callback)(gpointer data)

References _FlTaskRunnerTask::callback, _FlTaskRunnerTask::callback_data, and fl_task_runner_tasks_did_change_locked().

Referenced by fl_compositor_opengl_present_layers().

◆ fl_task_runner_post_flutter_task()

void fl_task_runner_post_flutter_task ( FlTaskRunner *  task_runner,
FlutterTask  task,
uint64_t  target_time_nanos 
)

fl_task_runner_post_flutter_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.

Definition at line 174 of file fl_task_runner.cc.

176  {
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);
187 }
static constexpr int kMicrosecondsPerNanosecond

References fl_task_runner_tasks_did_change_locked(), kMicrosecondsPerNanosecond, _FlTaskRunnerTask::task, and _FlTaskRunnerTask::task_time_micros.

Referenced by fl_engine_post_task().

◆ fl_task_runner_process_expired_tasks_locked()

static void fl_task_runner_process_expired_tasks_locked ( FlTaskRunner *  self)
static

Definition at line 43 of file fl_task_runner.cc.

43  {
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 }
void fl_engine_execute_task(FlEngine *self, FlutterTask *task)
Definition: fl_engine.cc:1424

References _FlTaskRunnerTask::callback, _FlTaskRunnerTask::callback_data, fl_engine_execute_task(), _FlTaskRunnerTask::task, and _FlTaskRunnerTask::task_time_micros.

Referenced by fl_task_runner_block_main_thread(), and fl_task_runner_on_expired_timeout().

◆ fl_task_runner_release_main_thread()

void fl_task_runner_release_main_thread ( FlTaskRunner *  self)

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.

Definition at line 224 of file fl_task_runner.cc.

224  {
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 }

References TRUE.

Referenced by fl_compositor_opengl_unblock_main_thread().

◆ fl_task_runner_tasks_did_change_locked()

static void fl_task_runner_tasks_did_change_locked ( FlTaskRunner *  self)
static

Definition at line 119 of file fl_task_runner.cc.

119  {
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,
135  }
136  }
137 }
static constexpr int kMillisecondsPerMicrosecond
static gboolean fl_task_runner_on_expired_timeout(gpointer data)

References fl_task_runner_next_task_expiration_time_locked(), fl_task_runner_on_expired_timeout(), and kMillisecondsPerMicrosecond.

Referenced by fl_task_runner_block_main_thread(), fl_task_runner_on_expired_timeout(), fl_task_runner_post_callback(), and fl_task_runner_post_flutter_task().

Variable Documentation

◆ kMicrosecondsPerNanosecond

constexpr int kMicrosecondsPerNanosecond = 1000
staticconstexpr

Definition at line 8 of file fl_task_runner.cc.

Referenced by fl_task_runner_post_flutter_task().

◆ kMillisecondsPerMicrosecond

constexpr int kMillisecondsPerMicrosecond = 1000
staticconstexpr

Definition at line 9 of file fl_task_runner.cc.

Referenced by fl_task_runner_tasks_did_change_locked().