• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 class TestWakeable : public fml::Wakeable {
15  public:
16   using WakeUpCall = std::function<void(const fml::TimePoint)>;
17 
TestWakeable(WakeUpCall call)18   TestWakeable(WakeUpCall call) : wake_up_call_(call) {}
19 
WakeUp(fml::TimePoint time_point)20   void WakeUp(fml::TimePoint time_point) override { wake_up_call_(time_point); }
21 
22  private:
23   WakeUpCall wake_up_call_;
24 };
25 
TEST(MessageLoopTaskQueueMergeUnmerge,AfterMergePrimaryTasksServicedOnPrimary)26 TEST(MessageLoopTaskQueueMergeUnmerge,
27      AfterMergePrimaryTasksServicedOnPrimary) {
28   auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
29 
30   auto queue_id_1 = task_queue->CreateTaskQueue();
31   auto queue_id_2 = task_queue->CreateTaskQueue();
32 
33   task_queue->RegisterTask(
34       queue_id_1, []() {}, fml::TimePoint::Now());
35   ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_1));
36 
37   task_queue->Merge(queue_id_1, queue_id_2);
38   task_queue->RegisterTask(
39       queue_id_1, []() {}, fml::TimePoint::Now());
40 
41   ASSERT_EQ(2u, task_queue->GetNumPendingTasks(queue_id_1));
42   ASSERT_EQ(0u, task_queue->GetNumPendingTasks(queue_id_2));
43 }
44 
TEST(MessageLoopTaskQueueMergeUnmerge,AfterMergeSecondaryTasksAlsoServicedOnPrimary)45 TEST(MessageLoopTaskQueueMergeUnmerge,
46      AfterMergeSecondaryTasksAlsoServicedOnPrimary) {
47   auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
48 
49   auto queue_id_1 = task_queue->CreateTaskQueue();
50   auto queue_id_2 = task_queue->CreateTaskQueue();
51 
52   task_queue->RegisterTask(
53       queue_id_2, []() {}, fml::TimePoint::Now());
54   ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_2));
55 
56   task_queue->Merge(queue_id_1, queue_id_2);
57   ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_1));
58   ASSERT_EQ(0u, task_queue->GetNumPendingTasks(queue_id_2));
59 }
60 
TEST(MessageLoopTaskQueueMergeUnmerge,MergeUnmergeTasksPreserved)61 TEST(MessageLoopTaskQueueMergeUnmerge, MergeUnmergeTasksPreserved) {
62   auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
63 
64   auto queue_id_1 = task_queue->CreateTaskQueue();
65   auto queue_id_2 = task_queue->CreateTaskQueue();
66 
67   task_queue->RegisterTask(
68       queue_id_1, []() {}, fml::TimePoint::Now());
69   task_queue->RegisterTask(
70       queue_id_2, []() {}, fml::TimePoint::Now());
71 
72   ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_1));
73   ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_2));
74 
75   task_queue->Merge(queue_id_1, queue_id_2);
76 
77   ASSERT_EQ(2u, task_queue->GetNumPendingTasks(queue_id_1));
78   ASSERT_EQ(0u, task_queue->GetNumPendingTasks(queue_id_2));
79 
80   task_queue->Unmerge(queue_id_1);
81 
82   ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_1));
83   ASSERT_EQ(1u, task_queue->GetNumPendingTasks(queue_id_2));
84 }
85 
TEST(MessageLoopTaskQueueMergeUnmerge,MergeFailIfAlreadyMergedOrSubsumed)86 TEST(MessageLoopTaskQueueMergeUnmerge, MergeFailIfAlreadyMergedOrSubsumed) {
87   auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
88 
89   auto queue_id_1 = task_queue->CreateTaskQueue();
90   auto queue_id_2 = task_queue->CreateTaskQueue();
91   auto queue_id_3 = task_queue->CreateTaskQueue();
92 
93   task_queue->Merge(queue_id_1, queue_id_2);
94 
95   ASSERT_FALSE(task_queue->Merge(queue_id_1, queue_id_3));
96   ASSERT_FALSE(task_queue->Merge(queue_id_2, queue_id_3));
97 }
98 
TEST(MessageLoopTaskQueueMergeUnmerge,UnmergeFailsOnSubsumed)99 TEST(MessageLoopTaskQueueMergeUnmerge, UnmergeFailsOnSubsumed) {
100   auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
101 
102   auto queue_id_1 = task_queue->CreateTaskQueue();
103   auto queue_id_2 = task_queue->CreateTaskQueue();
104 
105   task_queue->Merge(queue_id_1, queue_id_2);
106 
107   ASSERT_FALSE(task_queue->Unmerge(queue_id_2));
108 }
109 
TEST(MessageLoopTaskQueueMergeUnmerge,MergeInvokesBothWakeables)110 TEST(MessageLoopTaskQueueMergeUnmerge, MergeInvokesBothWakeables) {
111   auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
112 
113   auto queue_id_1 = task_queue->CreateTaskQueue();
114   auto queue_id_2 = task_queue->CreateTaskQueue();
115 
116   fml::CountDownLatch latch(2);
117 
118   task_queue->SetWakeable(
119       queue_id_1,
120       new TestWakeable([&](fml::TimePoint wake_time) { latch.CountDown(); }));
121   task_queue->SetWakeable(
122       queue_id_2,
123       new TestWakeable([&](fml::TimePoint wake_time) { latch.CountDown(); }));
124 
125   task_queue->RegisterTask(
126       queue_id_1, []() {}, fml::TimePoint::Now());
127 
128   task_queue->Merge(queue_id_1, queue_id_2);
129 
130   std::vector<fml::closure> invocations;
131   task_queue->GetTasksToRunNow(queue_id_1, fml::FlushType::kAll, invocations);
132 
133   latch.Wait();
134 }
135 
TEST(MessageLoopTaskQueueMergeUnmerge,MergeUnmergeInvokesBothWakeablesSeparately)136 TEST(MessageLoopTaskQueueMergeUnmerge,
137      MergeUnmergeInvokesBothWakeablesSeparately) {
138   auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
139 
140   auto queue_id_1 = task_queue->CreateTaskQueue();
141   auto queue_id_2 = task_queue->CreateTaskQueue();
142 
143   fml::AutoResetWaitableEvent latch_1, latch_2;
144 
145   task_queue->SetWakeable(
146       queue_id_1,
147       new TestWakeable([&](fml::TimePoint wake_time) { latch_1.Signal(); }));
148   task_queue->SetWakeable(
149       queue_id_2,
150       new TestWakeable([&](fml::TimePoint wake_time) { latch_2.Signal(); }));
151 
152   task_queue->RegisterTask(
153       queue_id_1, []() {}, fml::TimePoint::Now());
154   task_queue->RegisterTask(
155       queue_id_2, []() {}, fml::TimePoint::Now());
156 
157   task_queue->Merge(queue_id_1, queue_id_2);
158   task_queue->Unmerge(queue_id_1);
159 
160   std::vector<fml::closure> invocations;
161 
162   task_queue->GetTasksToRunNow(queue_id_1, fml::FlushType::kAll, invocations);
163   latch_1.Wait();
164 
165   task_queue->GetTasksToRunNow(queue_id_2, fml::FlushType::kAll, invocations);
166   latch_2.Wait();
167 }
168 
TEST(MessageLoopTaskQueueMergeUnmerge,GetTasksToRunNowBlocksMerge)169 TEST(MessageLoopTaskQueueMergeUnmerge, GetTasksToRunNowBlocksMerge) {
170   auto task_queue = fml::MessageLoopTaskQueues::GetInstance();
171 
172   auto queue_id_1 = task_queue->CreateTaskQueue();
173   auto queue_id_2 = task_queue->CreateTaskQueue();
174 
175   fml::AutoResetWaitableEvent wake_up_start, wake_up_end, merge_start,
176       merge_end;
177 
178   task_queue->RegisterTask(
179       queue_id_1, []() {}, fml::TimePoint::Now());
180   task_queue->SetWakeable(queue_id_1,
181                           new TestWakeable([&](fml::TimePoint wake_time) {
182                             wake_up_start.Signal();
183                             wake_up_end.Wait();
184                           }));
185 
186   std::thread tasks_to_run_now_thread([&]() {
187     std::vector<fml::closure> invocations;
188     task_queue->GetTasksToRunNow(queue_id_1, fml::FlushType::kAll, invocations);
189   });
190 
191   wake_up_start.Wait();
192   bool merge_done = false;
193 
194   std::thread merge_thread([&]() {
195     merge_start.Signal();
196     task_queue->Merge(queue_id_1, queue_id_2);
197     merge_done = true;
198     merge_end.Signal();
199   });
200 
201   merge_start.Wait();
202   ASSERT_FALSE(merge_done);
203   wake_up_end.Signal();
204 
205   merge_end.Wait();
206   ASSERT_TRUE(merge_done);
207 
208   tasks_to_run_now_thread.join();
209   merge_thread.join();
210 }
211