5#define FML_USED_ON_EMBEDDER
7#include "flutter/fml/message_loop_task_queues.h"
14#include "flutter/fml/synchronization/count_down_latch.h"
15#include "flutter/fml/synchronization/waitable_event.h"
16#include "flutter/fml/time/chrono_timestamp_provider.h"
17#include "gtest/gtest.h"
34TEST(MessageLoopTaskQueue, StartsWithNoPendingTasks) {
36 auto queue_id = task_queue->CreateTaskQueue();
37 ASSERT_FALSE(task_queue->HasPendingTasks(queue_id));
40TEST(MessageLoopTaskQueue, RegisterOneTask) {
44 auto queue_id = task_queue->CreateTaskQueue();
45 auto wakeable = std::make_unique<TestWakeable>(
47 task_queue->SetWakeable(queue_id, wakeable.get());
49 task_queue->RegisterTask(queue_id, [] {},
time);
50 ASSERT_TRUE(task_queue->HasPendingTasks(queue_id));
51 ASSERT_TRUE(task_queue->GetNumPendingTasks(queue_id) == 1);
54TEST(MessageLoopTaskQueue, RegisterTwoTasksAndCount) {
56 auto queue_id = task_queue->CreateTaskQueue();
59 ASSERT_TRUE(task_queue->HasPendingTasks(queue_id));
60 ASSERT_TRUE(task_queue->GetNumPendingTasks(queue_id) == 2);
63TEST(MessageLoopTaskQueue, RegisterTasksOnMergedQueuesAndCount) {
65 auto platform_queue = task_queue->CreateTaskQueue();
66 auto raster_queue = task_queue->CreateTaskQueue();
71 ASSERT_TRUE(task_queue->GetNumPendingTasks(platform_queue) == 1);
72 ASSERT_TRUE(task_queue->GetNumPendingTasks(raster_queue) == 1);
74 ASSERT_FALSE(task_queue->Owns(platform_queue, raster_queue));
75 task_queue->Merge(platform_queue, raster_queue);
76 ASSERT_TRUE(task_queue->Owns(platform_queue, raster_queue));
78 ASSERT_TRUE(task_queue->HasPendingTasks(platform_queue));
79 ASSERT_TRUE(task_queue->GetNumPendingTasks(platform_queue) == 2);
81 ASSERT_FALSE(task_queue->HasPendingTasks(raster_queue));
82 ASSERT_TRUE(task_queue->GetNumPendingTasks(raster_queue) == 0);
84 task_queue->Unmerge(platform_queue, raster_queue);
85 ASSERT_FALSE(task_queue->Owns(platform_queue, raster_queue));
86 ASSERT_TRUE(task_queue->GetNumPendingTasks(platform_queue) == 1);
87 ASSERT_TRUE(task_queue->GetNumPendingTasks(raster_queue) == 1);
90TEST(MessageLoopTaskQueue, PreserveTaskOrdering) {
92 auto queue_id = task_queue->CreateTaskQueue();
96 task_queue->RegisterTask(
100 task_queue->RegisterTask(
106 fml::closure invocation = task_queue->GetNextTaskToRun(queue_id, now);
116TEST(MessageLoopTaskQueue, RegisterTasksOnMergedQueuesPreserveTaskOrdering) {
118 auto platform_queue = task_queue->CreateTaskQueue();
119 auto raster1_queue = task_queue->CreateTaskQueue();
120 auto raster2_queue = task_queue->CreateTaskQueue();
124 task_queue->RegisterTask(
128 task_queue->RegisterTask(
132 task_queue->RegisterTask(
135 task_queue->Merge(platform_queue, raster1_queue);
136 ASSERT_TRUE(task_queue->Owns(platform_queue, raster1_queue));
137 task_queue->Merge(platform_queue, raster2_queue);
138 ASSERT_TRUE(task_queue->Owns(platform_queue, raster2_queue));
146 fml::closure invocation = task_queue->GetNextTaskToRun(platform_queue, now);
156TEST(MessageLoopTaskQueue, UnmergeRespectTheOriginalTaskOrderingInQueues) {
158 auto platform_queue = task_queue->CreateTaskQueue();
159 auto raster_queue = task_queue->CreateTaskQueue();
163 task_queue->RegisterTask(
166 task_queue->RegisterTask(
169 task_queue->RegisterTask(
172 task_queue->RegisterTask(
175 task_queue->RegisterTask(
178 task_queue->RegisterTask(
181 ASSERT_TRUE(task_queue->Merge(platform_queue, raster_queue));
182 ASSERT_TRUE(task_queue->Owns(platform_queue, raster_queue));
188 for (
int i = 0;
i < 3;
i++) {
189 fml::closure invocation = task_queue->GetNextTaskToRun(platform_queue, now);
190 ASSERT_FALSE(!invocation);
192 ASSERT_TRUE(test_val ==
i);
194 ASSERT_TRUE(task_queue->GetNumPendingTasks(platform_queue) == 3);
195 ASSERT_TRUE(task_queue->GetNumPendingTasks(raster_queue) == 0);
197 ASSERT_TRUE(task_queue->Unmerge(platform_queue, raster_queue));
198 ASSERT_FALSE(task_queue->Owns(platform_queue, raster_queue));
207 ASSERT_TRUE(task_queue->GetNumPendingTasks(platform_queue) == 1);
208 fml::closure invocation = task_queue->GetNextTaskToRun(platform_queue, now);
209 ASSERT_FALSE(!invocation);
211 ASSERT_TRUE(test_val == 4);
212 ASSERT_TRUE(task_queue->GetNumPendingTasks(platform_queue) == 0);
217 ASSERT_TRUE(task_queue->GetNumPendingTasks(raster_queue) == 2);
218 fml::closure invocation = task_queue->GetNextTaskToRun(raster_queue, now);
219 ASSERT_FALSE(!invocation);
221 ASSERT_TRUE(test_val == 3);
224 ASSERT_TRUE(task_queue->GetNumPendingTasks(raster_queue) == 1);
225 fml::closure invocation = task_queue->GetNextTaskToRun(raster_queue, now);
226 ASSERT_FALSE(!invocation);
228 ASSERT_TRUE(test_val == 5);
229 ASSERT_TRUE(task_queue->GetNumPendingTasks(raster_queue) == 0);
235 std::vector<fml::closure> observers =
236 task_queue->GetObserversToNotify(queue_id);
237 for (
const auto& observer : observers) {
242TEST(MessageLoopTaskQueue, AddRemoveNotifyObservers) {
244 auto queue_id = task_queue->CreateTaskQueue();
249 task_queue->AddTaskObserver(queue_id,
key, [&test_val]() { test_val = 1; });
251 ASSERT_TRUE(test_val == 1);
254 task_queue->RemoveTaskObserver(queue_id,
key);
256 ASSERT_TRUE(test_val == 0);
259TEST(MessageLoopTaskQueue, WakeUpIndependentOfTime) {
261 auto queue_id = task_queue->CreateTaskQueue();
264 auto wakeable = std::make_unique<TestWakeable>(
266 task_queue->SetWakeable(queue_id, wakeable.get());
271 ASSERT_TRUE(num_wakes == 2);
274TEST(MessageLoopTaskQueue, WokenUpWithNewerTime) {
276 auto queue_id = task_queue->CreateTaskQueue();
281 auto wakeable = std::make_unique<TestWakeable>(
283 ASSERT_TRUE(wake_time == expected);
287 task_queue->SetWakeable(queue_id, wakeable.get());
293 task_queue->RegisterTask(queue_id, []() {}, now);
298TEST(MessageLoopTaskQueue, NotifyObserversWhileCreatingQueues) {
303 task_queues->AddTaskObserver(queue_id, queue_id + 1, [&]() {
304 first_observer_executing.
Signal();
305 before_second_observer.
Wait();
308 for (
int i = 0;
i < 100;
i++) {
309 task_queues->AddTaskObserver(queue_id, queue_id +
i + 2, [] {});
314 first_observer_executing.
Wait();
316 for (
int i = 0;
i < 100;
i++) {
317 task_queues->CreateTaskQueue();
320 before_second_observer.
Signal();
321 notify_observers.join();
324TEST(MessageLoopTaskQueue, QueueDoNotOwnItself) {
326 auto queue_id = task_queue->CreateTaskQueue();
327 ASSERT_FALSE(task_queue->Owns(queue_id, queue_id));
330TEST(MessageLoopTaskQueue, QueueDoNotOwnUnmergedTaskQueueId) {
332 ASSERT_FALSE(task_queue->Owns(task_queue->CreateTaskQueue(),
kUnmerged));
333 ASSERT_FALSE(task_queue->Owns(
kUnmerged, task_queue->CreateTaskQueue()));
337TEST(MessageLoopTaskQueue, QueueOwnsMergedTaskQueueId) {
339 auto platform_queue = task_queue->CreateTaskQueue();
340 auto raster_queue = task_queue->CreateTaskQueue();
341 ASSERT_FALSE(task_queue->Owns(platform_queue, raster_queue));
342 ASSERT_FALSE(task_queue->Owns(raster_queue, platform_queue));
343 task_queue->Merge(platform_queue, raster_queue);
344 ASSERT_TRUE(task_queue->Owns(platform_queue, raster_queue));
345 ASSERT_FALSE(task_queue->Owns(raster_queue, platform_queue));
351TEST(MessageLoopTaskQueue, ConcurrentQueueAndTaskCreatingCounts) {
357 constexpr size_t kTaskQueuesCount = 2;
358 constexpr size_t kThreadTaskCount = 500;
360 std::vector<TaskQueueId> task_queue_ids;
361 for (
size_t i = 0;
i < kTaskQueuesCount; ++
i) {
362 task_queue_ids.emplace_back(task_queues->CreateTaskQueue());
365 ASSERT_EQ(task_queue_ids.size(), kTaskQueuesCount);
369 auto thread_main = [&]() {
370 for (
size_t i = 0;
i < kThreadTaskCount;
i++) {
371 const auto current_task_queue_id =
372 task_queue_ids[std::rand() % kTaskQueuesCount];
373 const auto empty_task = []() {};
377 task_queues->RegisterTask(current_task_queue_id, empty_task,
384 std::vector<std::thread> threads;
387 threads.emplace_back(std::thread{thread_main});
398 size_t pending_tasks = 0u;
399 std::for_each(task_queue_ids.begin(), task_queue_ids.end(),
400 [&](
const auto&
queue) {
401 pending_tasks += task_queues->GetNumPendingTasks(queue);
404 ASSERT_EQ(pending_tasks,
kThreadCount * kThreadTaskCount);
407TEST(MessageLoopTaskQueue, RegisterTaskWakesUpOwnerQueue) {
409 auto platform_queue = task_queue->CreateTaskQueue();
410 auto raster_queue = task_queue->CreateTaskQueue();
412 std::vector<fml::TimePoint> wakes;
414 auto wakeable1 = std::make_unique<TestWakeable>(
415 [&wakes](
fml::TimePoint wake_time) { wakes.push_back(wake_time); });
416 auto wakeable2 = std::make_unique<TestWakeable>([](
fml::TimePoint wake_time) {
421 task_queue->SetWakeable(platform_queue, wakeable1.get());
422 task_queue->SetWakeable(raster_queue, wakeable2.get());
427 ASSERT_EQ(0
UL, wakes.size());
429 task_queue->RegisterTask(platform_queue, []() {}, time1);
431 ASSERT_EQ(1UL, wakes.size());
432 ASSERT_EQ(time1, wakes[0]);
434 task_queue->Merge(platform_queue, raster_queue);
436 task_queue->RegisterTask(raster_queue, []() {}, time2);
438 ASSERT_EQ(3UL, wakes.size());
439 ASSERT_EQ(time1, wakes[1]);
440 ASSERT_EQ(time1, wakes[2]);
static MessageLoopTaskQueues * GetInstance()
static constexpr TimeDelta FromMilliseconds(int64_t millis)
static constexpr TimePoint Max()
void WakeUp(fml::TimePoint time_point) override
std::function< void(const fml::TimePoint)> WakeUpCall
TestWakeable(WakeUpCall call)
static const char * expected_value
static constexpr uint64_t kThreadCount
Dart_NativeFunction function
TEST(BacktraceTest, CanGatherBacktrace)
void TestNotifyObservers(fml::TaskQueueId queue_id)
static const TaskQueueId kUnmerged
fml::TimePoint ChronoTicksSinceEpoch()
std::function< void()> closure
static double time(int loops, Benchmark *bench, Target *target)