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 "gtest/gtest.h"
13 
14 namespace fml {
15 namespace testing {
16 
17 class TestWakeable : public fml::Wakeable {
18  public:
19  using WakeUpCall = std::function<void(const fml::TimePoint)>;
20 
21  explicit TestWakeable(WakeUpCall call) : wake_up_call_(call) {}
22 
23  void WakeUp(fml::TimePoint time_point) override { wake_up_call_(time_point); }
24 
25  private:
26  WakeUpCall wake_up_call_;
27 };
28 
30  const TaskQueueId& queue_id,
31  bool run_invocation = false) {
32  const auto now = fml::TimePoint::Now();
33  int count = 0;
34  fml::closure invocation;
35  do {
36  invocation = task_queue->GetNextTaskToRun(queue_id, now);
37  if (!invocation) {
38  break;
39  }
40  count++;
41  if (run_invocation) {
42  invocation();
43  }
44  } while (invocation);
45  return count;
46 }
47 
48 TEST(MessageLoopTaskQueueMergeUnmerge,
49  AfterMergePrimaryTasksServicedOnPrimary) {
50  auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
51 
52  auto queue_id_1 = task_queue->CreateTaskQueue();
53  auto queue_id_2 = task_queue->CreateTaskQueue();
54 
55  task_queue->RegisterTask(
56  queue_id_1, []() {}, fml::TimePoint::Now());
57  ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_1));
58 
59  task_queue->Merge(queue_id_1, queue_id_2);
60  task_queue->RegisterTask(
61  queue_id_1, []() {}, fml::TimePoint::Now());
62 
63  ASSERT_EQ(2u, task_queue->GetNumPendingTasks(queue_id_1));
64  ASSERT_EQ(0u, task_queue->GetNumPendingTasks(queue_id_2));
65 }
66 
67 TEST(MessageLoopTaskQueueMergeUnmerge,
68  AfterMergeSecondaryTasksAlsoServicedOnPrimary) {
69  auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
70 
71  auto queue_id_1 = task_queue->CreateTaskQueue();
72  auto queue_id_2 = task_queue->CreateTaskQueue();
73 
74  task_queue->RegisterTask(
75  queue_id_2, []() {}, fml::TimePoint::Now());
76  ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_2));
77 
78  task_queue->Merge(queue_id_1, queue_id_2);
79  ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_1));
80  ASSERT_EQ(0u, task_queue->GetNumPendingTasks(queue_id_2));
81 }
82 
83 TEST(MessageLoopTaskQueueMergeUnmerge, MergeUnmergeTasksPreserved) {
84  auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
85 
86  auto queue_id_1 = task_queue->CreateTaskQueue();
87  auto queue_id_2 = task_queue->CreateTaskQueue();
88 
89  task_queue->RegisterTask(
90  queue_id_1, []() {}, fml::TimePoint::Now());
91  task_queue->RegisterTask(
92  queue_id_2, []() {}, fml::TimePoint::Now());
93 
94  ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_1));
95  ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_2));
96 
97  task_queue->Merge(queue_id_1, queue_id_2);
98 
99  ASSERT_EQ(2u, task_queue->GetNumPendingTasks(queue_id_1));
100  ASSERT_EQ(0u, task_queue->GetNumPendingTasks(queue_id_2));
101 
102  task_queue->Unmerge(queue_id_1);
103 
104  ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_1));
105  ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_2));
106 }
107 
108 TEST(MessageLoopTaskQueueMergeUnmerge, MergeFailIfAlreadyMergedOrSubsumed) {
109  auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
110 
111  auto queue_id_1 = task_queue->CreateTaskQueue();
112  auto queue_id_2 = task_queue->CreateTaskQueue();
113  auto queue_id_3 = task_queue->CreateTaskQueue();
114 
115  task_queue->Merge(queue_id_1, queue_id_2);
116 
117  ASSERT_FALSE(task_queue->Merge(queue_id_1, queue_id_3));
118  ASSERT_FALSE(task_queue->Merge(queue_id_2, queue_id_3));
119 }
120 
121 TEST(MessageLoopTaskQueueMergeUnmerge, UnmergeFailsOnSubsumed) {
122  auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
123 
124  auto queue_id_1 = task_queue->CreateTaskQueue();
125  auto queue_id_2 = task_queue->CreateTaskQueue();
126 
127  task_queue->Merge(queue_id_1, queue_id_2);
128 
129  ASSERT_FALSE(task_queue->Unmerge(queue_id_2));
130 }
131 
132 TEST(MessageLoopTaskQueueMergeUnmerge, MergeInvokesBothWakeables) {
133  auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
134 
135  auto queue_id_1 = task_queue->CreateTaskQueue();
136  auto queue_id_2 = task_queue->CreateTaskQueue();
137 
138  fml::CountDownLatch latch(2);
139 
140  task_queue->SetWakeable(
141  queue_id_1,
142  new TestWakeable([&](fml::TimePoint wake_time) { latch.CountDown(); }));
143  task_queue->SetWakeable(
144  queue_id_2,
145  new TestWakeable([&](fml::TimePoint wake_time) { latch.CountDown(); }));
146 
147  task_queue->RegisterTask(
148  queue_id_1, []() {}, fml::TimePoint::Now());
149 
150  task_queue->Merge(queue_id_1, queue_id_2);
151 
152  CountRemainingTasks(task_queue, queue_id_1);
153 
154  latch.Wait();
155 }
156 
157 TEST(MessageLoopTaskQueueMergeUnmerge,
158  MergeUnmergeInvokesBothWakeablesSeparately) {
159  auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
160 
161  auto queue_id_1 = task_queue->CreateTaskQueue();
162  auto queue_id_2 = task_queue->CreateTaskQueue();
163 
164  fml::AutoResetWaitableEvent latch_1, latch_2;
165 
166  task_queue->SetWakeable(
167  queue_id_1,
168  new TestWakeable([&](fml::TimePoint wake_time) { latch_1.Signal(); }));
169  task_queue->SetWakeable(
170  queue_id_2,
171  new TestWakeable([&](fml::TimePoint wake_time) { latch_2.Signal(); }));
172 
173  task_queue->RegisterTask(
174  queue_id_1, []() {}, fml::TimePoint::Now());
175  task_queue->RegisterTask(
176  queue_id_2, []() {}, fml::TimePoint::Now());
177 
178  task_queue->Merge(queue_id_1, queue_id_2);
179  task_queue->Unmerge(queue_id_1);
180 
181  CountRemainingTasks(task_queue, queue_id_1);
182 
183  latch_1.Wait();
184 
185  CountRemainingTasks(task_queue, queue_id_2);
186 
187  latch_2.Wait();
188 }
189 
190 TEST(MessageLoopTaskQueueMergeUnmerge, GetTasksToRunNowBlocksMerge) {
191  auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
192 
193  auto queue_id_1 = task_queue->CreateTaskQueue();
194  auto queue_id_2 = task_queue->CreateTaskQueue();
195 
196  fml::AutoResetWaitableEvent wake_up_start, wake_up_end, merge_start,
197  merge_end;
198 
199  task_queue->RegisterTask(
200  queue_id_1, []() {}, fml::TimePoint::Now());
201  task_queue->SetWakeable(queue_id_1,
202  new TestWakeable([&](fml::TimePoint wake_time) {
203  wake_up_start.Signal();
204  wake_up_end.Wait();
205  }));
206 
207  std::thread tasks_to_run_now_thread(
208  [&]() { CountRemainingTasks(task_queue, queue_id_1); });
209 
210  wake_up_start.Wait();
211  bool merge_done = false;
212 
213  std::thread merge_thread([&]() {
214  merge_start.Signal();
215  task_queue->Merge(queue_id_1, queue_id_2);
216  merge_done = true;
217  merge_end.Signal();
218  });
219 
220  merge_start.Wait();
221  ASSERT_FALSE(merge_done);
222  wake_up_end.Signal();
223 
224  merge_end.Wait();
225  ASSERT_TRUE(merge_done);
226 
227  tasks_to_run_now_thread.join();
228  merge_thread.join();
229 }
230 
231 TEST(MessageLoopTaskQueueMergeUnmerge,
232  FollowingTasksSwitchQueueIfFirstTaskMergesThreads) {
233  auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
234 
235  auto queue_id_1 = task_queue->CreateTaskQueue();
236  auto queue_id_2 = task_queue->CreateTaskQueue();
237 
238  fml::CountDownLatch latch(2);
239 
240  task_queue->SetWakeable(
241  queue_id_1,
242  new TestWakeable([&](fml::TimePoint wake_time) { latch.CountDown(); }));
243  task_queue->SetWakeable(
244  queue_id_2,
245  new TestWakeable([&](fml::TimePoint wake_time) { latch.CountDown(); }));
246 
247  task_queue->RegisterTask(
248  queue_id_2, [&]() { task_queue->Merge(queue_id_1, queue_id_2); },
250 
251  task_queue->RegisterTask(
252  queue_id_2, []() {}, fml::TimePoint::Now());
253 
254  ASSERT_EQ(CountRemainingTasks(task_queue, queue_id_2, true), 1);
255  ASSERT_EQ(CountRemainingTasks(task_queue, queue_id_1, true), 1);
256 
257  latch.Wait();
258 }
259 
260 } // namespace testing
261 } // 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()
static int CountRemainingTasks(fml::RefPtr< MessageLoopTaskQueues > task_queue, const TaskQueueId &queue_id, bool run_invocation=false)
static TimePoint Now()
Definition: time_point.cc:26