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