Flutter Engine
The Flutter Engine
message_loop_task_queues_merge_unmerge_unittests.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#define FML_USED_ON_EMBEDDER
6
7#include <thread>
8#include <utility>
9
10#include "flutter/fml/message_loop_task_queues.h"
11#include "flutter/fml/synchronization/count_down_latch.h"
12#include "flutter/fml/synchronization/waitable_event.h"
13#include "flutter/fml/time/chrono_timestamp_provider.h"
14#include "gtest/gtest.h"
15
16namespace fml {
17namespace testing {
18
20 public:
22
23 explicit TestWakeable(WakeUpCall call) : wake_up_call_(std::move(call)) {}
24
25 void WakeUp(fml::TimePoint time_point) override { wake_up_call_(time_point); }
26
27 private:
28 WakeUpCall wake_up_call_;
29};
30
32 const TaskQueueId& queue_id,
33 bool run_invocation = false) {
34 const auto now = ChronoTicksSinceEpoch();
35 int count = 0;
36 fml::closure invocation;
37 do {
38 invocation = task_queue->GetNextTaskToRun(queue_id, now);
39 if (!invocation) {
40 break;
41 }
42 count++;
43 if (run_invocation) {
44 invocation();
45 }
46 } while (invocation);
47 return count;
48}
49
50TEST(MessageLoopTaskQueueMergeUnmerge,
51 AfterMergePrimaryTasksServicedOnPrimary) {
53
54 auto queue_id_1 = task_queue->CreateTaskQueue();
55 auto queue_id_2 = task_queue->CreateTaskQueue();
56
57 task_queue->RegisterTask(queue_id_1, []() {}, ChronoTicksSinceEpoch());
58 ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_1));
59
60 task_queue->Merge(queue_id_1, queue_id_2);
61 task_queue->RegisterTask(queue_id_1, []() {}, ChronoTicksSinceEpoch());
62
63 ASSERT_EQ(2u, task_queue->GetNumPendingTasks(queue_id_1));
64 ASSERT_EQ(0u, task_queue->GetNumPendingTasks(queue_id_2));
65}
66
67TEST(MessageLoopTaskQueueMergeUnmerge,
68 AfterMergeSecondaryTasksAlsoServicedOnPrimary) {
70
71 auto queue_id_1 = task_queue->CreateTaskQueue();
72 auto queue_id_2 = task_queue->CreateTaskQueue();
73
74 task_queue->RegisterTask(queue_id_2, []() {}, ChronoTicksSinceEpoch());
75 ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_2));
76
77 task_queue->Merge(queue_id_1, queue_id_2);
78 ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_1));
79 ASSERT_EQ(0u, task_queue->GetNumPendingTasks(queue_id_2));
80}
81
82TEST(MessageLoopTaskQueueMergeUnmerge, MergeUnmergeTasksPreserved) {
84
85 auto queue_id_1 = task_queue->CreateTaskQueue();
86 auto queue_id_2 = task_queue->CreateTaskQueue();
87
88 task_queue->RegisterTask(queue_id_1, []() {}, ChronoTicksSinceEpoch());
89 task_queue->RegisterTask(queue_id_2, []() {}, ChronoTicksSinceEpoch());
90
91 ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_1));
92 ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_2));
93
94 task_queue->Merge(queue_id_1, queue_id_2);
95
96 ASSERT_EQ(2u, task_queue->GetNumPendingTasks(queue_id_1));
97 ASSERT_EQ(0u, task_queue->GetNumPendingTasks(queue_id_2));
98
99 task_queue->Unmerge(queue_id_1, queue_id_2);
100
101 ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_1));
102 ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_2));
103}
104
105/// Multiple standalone engines scene
106TEST(MessageLoopTaskQueueMergeUnmerge,
107 OneCanOwnMultipleQueuesAndUnmergeIndependently) {
108 auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
109 auto queue_id_1 = task_queue->CreateTaskQueue();
110 auto queue_id_2 = task_queue->CreateTaskQueue();
111 auto queue_id_3 = task_queue->CreateTaskQueue();
112
113 // merge
114 ASSERT_TRUE(task_queue->Merge(queue_id_1, queue_id_2));
115 ASSERT_TRUE(task_queue->Owns(queue_id_1, queue_id_2));
116 ASSERT_FALSE(task_queue->Owns(queue_id_1, queue_id_3));
117
118 ASSERT_TRUE(task_queue->Merge(queue_id_1, queue_id_3));
119 ASSERT_TRUE(task_queue->Owns(queue_id_1, queue_id_2));
120 ASSERT_TRUE(task_queue->Owns(queue_id_1, queue_id_3));
121
122 // unmerge
123 ASSERT_TRUE(task_queue->Unmerge(queue_id_1, queue_id_2));
124 ASSERT_FALSE(task_queue->Owns(queue_id_1, queue_id_2));
125 ASSERT_TRUE(task_queue->Owns(queue_id_1, queue_id_3));
126
127 ASSERT_TRUE(task_queue->Unmerge(queue_id_1, queue_id_3));
128 ASSERT_FALSE(task_queue->Owns(queue_id_1, queue_id_2));
129 ASSERT_FALSE(task_queue->Owns(queue_id_1, queue_id_3));
130}
131
132TEST(MessageLoopTaskQueueMergeUnmerge,
133 CannotMergeSameQueueToTwoDifferentOwners) {
134 auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
135 auto queue = task_queue->CreateTaskQueue();
136 auto owner_1 = task_queue->CreateTaskQueue();
137 auto owner_2 = task_queue->CreateTaskQueue();
138
139 ASSERT_TRUE(task_queue->Merge(owner_1, queue));
140 ASSERT_FALSE(task_queue->Merge(owner_2, queue));
141}
142
143TEST(MessageLoopTaskQueueMergeUnmerge, MergeFailIfAlreadySubsumed) {
144 auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
145
146 auto queue_id_1 = task_queue->CreateTaskQueue();
147 auto queue_id_2 = task_queue->CreateTaskQueue();
148 auto queue_id_3 = task_queue->CreateTaskQueue();
149
150 ASSERT_TRUE(task_queue->Merge(queue_id_1, queue_id_2));
151 ASSERT_FALSE(task_queue->Merge(queue_id_2, queue_id_3));
152 ASSERT_FALSE(task_queue->Merge(queue_id_2, queue_id_1));
153}
154
155TEST(MessageLoopTaskQueueMergeUnmerge,
156 MergeFailIfAlreadyOwnsButTryToBeSubsumed) {
157 auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
158
159 auto queue_id_1 = task_queue->CreateTaskQueue();
160 auto queue_id_2 = task_queue->CreateTaskQueue();
161 auto queue_id_3 = task_queue->CreateTaskQueue();
162
163 task_queue->Merge(queue_id_1, queue_id_2);
164 // A recursively linked merging will fail
165 ASSERT_FALSE(task_queue->Merge(queue_id_3, queue_id_1));
166}
167
168TEST(MessageLoopTaskQueueMergeUnmerge, UnmergeFailsOnSubsumedOrNeverMerged) {
169 auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
170
171 auto queue_id_1 = task_queue->CreateTaskQueue();
172 auto queue_id_2 = task_queue->CreateTaskQueue();
173 auto queue_id_3 = task_queue->CreateTaskQueue();
174
175 task_queue->Merge(queue_id_1, queue_id_2);
176 ASSERT_FALSE(task_queue->Unmerge(queue_id_2, queue_id_3));
177 ASSERT_FALSE(task_queue->Unmerge(queue_id_1, queue_id_3));
178 ASSERT_FALSE(task_queue->Unmerge(queue_id_3, queue_id_1));
179 ASSERT_FALSE(task_queue->Unmerge(queue_id_2, queue_id_1));
180}
181
182TEST(MessageLoopTaskQueueMergeUnmerge, MergeInvokesBothWakeables) {
183 auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
184
185 auto queue_id_1 = task_queue->CreateTaskQueue();
186 auto queue_id_2 = task_queue->CreateTaskQueue();
187
188 fml::CountDownLatch latch(2);
189
190 auto wakeable1 = std::make_unique<TestWakeable>(
191 [&](fml::TimePoint wake_time) { latch.CountDown(); });
192 auto wakeable2 = std::make_unique<TestWakeable>(
193 [&](fml::TimePoint wake_time) { latch.CountDown(); });
194
195 task_queue->SetWakeable(queue_id_1, wakeable1.get());
196 task_queue->SetWakeable(queue_id_2, wakeable2.get());
197
198 task_queue->RegisterTask(queue_id_1, []() {}, ChronoTicksSinceEpoch());
199
200 task_queue->Merge(queue_id_1, queue_id_2);
201
202 CountRemainingTasks(task_queue, queue_id_1);
203
204 latch.Wait();
205}
206
207TEST(MessageLoopTaskQueueMergeUnmerge,
208 MergeUnmergeInvokesBothWakeablesSeparately) {
209 auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
210
211 auto queue_id_1 = task_queue->CreateTaskQueue();
212 auto queue_id_2 = task_queue->CreateTaskQueue();
213
214 fml::AutoResetWaitableEvent latch_1, latch_2;
215
216 auto wakeable1 = std::make_unique<TestWakeable>(
217 [&](fml::TimePoint wake_time) { latch_1.Signal(); });
218 auto wakeable2 = std::make_unique<TestWakeable>(
219 [&](fml::TimePoint wake_time) { latch_2.Signal(); });
220
221 task_queue->SetWakeable(queue_id_1, wakeable1.get());
222 task_queue->SetWakeable(queue_id_2, wakeable2.get());
223
224 task_queue->RegisterTask(queue_id_1, []() {}, ChronoTicksSinceEpoch());
225 task_queue->RegisterTask(queue_id_2, []() {}, ChronoTicksSinceEpoch());
226
227 task_queue->Merge(queue_id_1, queue_id_2);
228 task_queue->Unmerge(queue_id_1, queue_id_2);
229
230 CountRemainingTasks(task_queue, queue_id_1);
231
232 latch_1.Wait();
233
234 CountRemainingTasks(task_queue, queue_id_2);
235
236 latch_2.Wait();
237}
238
239TEST(MessageLoopTaskQueueMergeUnmerge, GetTasksToRunNowBlocksMerge) {
240 auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
241
242 auto queue_id_1 = task_queue->CreateTaskQueue();
243 auto queue_id_2 = task_queue->CreateTaskQueue();
244
245 fml::AutoResetWaitableEvent wake_up_start, wake_up_end, merge_start,
246 merge_end;
247
248 auto wakeable = std::make_unique<TestWakeable>([&](fml::TimePoint wake_time) {
249 wake_up_start.Signal();
250 wake_up_end.Wait();
251 });
252
253 task_queue->RegisterTask(queue_id_1, []() {}, ChronoTicksSinceEpoch());
254 task_queue->SetWakeable(queue_id_1, wakeable.get());
255
256 std::thread tasks_to_run_now_thread(
257 [&]() { CountRemainingTasks(task_queue, queue_id_1); });
258
259 wake_up_start.Wait();
260 bool merge_done = false;
261
262 std::thread merge_thread([&]() {
263 merge_start.Signal();
264 task_queue->Merge(queue_id_1, queue_id_2);
265 merge_done = true;
266 merge_end.Signal();
267 });
268
269 merge_start.Wait();
270 ASSERT_FALSE(merge_done);
271 wake_up_end.Signal();
272
273 merge_end.Wait();
274 ASSERT_TRUE(merge_done);
275
276 tasks_to_run_now_thread.join();
277 merge_thread.join();
278}
279
280TEST(MessageLoopTaskQueueMergeUnmerge,
281 FollowingTasksSwitchQueueIfFirstTaskMergesThreads) {
282 auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
283
284 auto queue_id_1 = task_queue->CreateTaskQueue();
285 auto queue_id_2 = task_queue->CreateTaskQueue();
286
287 fml::CountDownLatch latch(2);
288
289 auto wakeable1 = std::make_unique<TestWakeable>(
290 [&](fml::TimePoint wake_time) { latch.CountDown(); });
291 auto wakeable2 = std::make_unique<TestWakeable>(
292 [&](fml::TimePoint wake_time) { latch.CountDown(); });
293
294 task_queue->SetWakeable(queue_id_1, wakeable1.get());
295 task_queue->SetWakeable(queue_id_2, wakeable2.get());
296
297 task_queue->RegisterTask(
298 queue_id_2, [&]() { task_queue->Merge(queue_id_1, queue_id_2); },
300
301 task_queue->RegisterTask(queue_id_2, []() {}, ChronoTicksSinceEpoch());
302
303 ASSERT_EQ(CountRemainingTasks(task_queue, queue_id_2, true), 1);
304 ASSERT_EQ(CountRemainingTasks(task_queue, queue_id_1, true), 1);
305
306 latch.Wait();
307}
308
309} // namespace testing
310} // namespace fml
int count
Definition: FontMgrTest.cpp:50
fml::closure GetNextTaskToRun(TaskQueueId queue_id, fml::TimePoint from_time)
static MessageLoopTaskQueues * GetInstance()
void WakeUp(fml::TimePoint time_point) override
std::function< void(const fml::TimePoint)> WakeUpCall
VkQueue queue
Definition: main.cc:55
Dart_NativeFunction function
Definition: fuchsia.cc:51
def call(args)
Definition: dom.py:159
static int CountRemainingTasks(fml::MessageLoopTaskQueues *task_queue, const TaskQueueId &queue_id, bool run_invocation=false)
TEST(BacktraceTest, CanGatherBacktrace)
Definition: ascii_trie.cc:9
fml::TimePoint ChronoTicksSinceEpoch()
std::function< void()> closure
Definition: closure.h:14
Definition: ref_ptr.h:256