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 <gtest/gtest.h>
8
9#include <thread>
10#include "flutter/fml/memory/task_runner_checker.h"
11
12#include "flutter/fml/message_loop.h"
13#include "flutter/fml/raster_thread_merger.h"
14#include "flutter/fml/synchronization/count_down_latch.h"
15#include "flutter/fml/synchronization/waitable_event.h"
16
17namespace fml {
18namespace testing {
19
20TEST(TaskRunnerCheckerTests, RunsOnCurrentTaskRunner) {
21 TaskRunnerChecker checker;
22 EXPECT_EQ(checker.RunsOnCreationTaskRunner(), true);
23}
24
25TEST(TaskRunnerCheckerTests, FailsTheCheckIfOnDifferentTaskRunner) {
26 TaskRunnerChecker checker;
27 EXPECT_EQ(checker.RunsOnCreationTaskRunner(), true);
28 fml::MessageLoop* loop = nullptr;
29 fml::AutoResetWaitableEvent latch;
30 std::thread anotherThread([&]() {
31 fml::MessageLoop::EnsureInitializedForCurrentThread();
32 loop = &fml::MessageLoop::GetCurrent();
33 loop->GetTaskRunner()->PostTask([&]() {
34 EXPECT_EQ(checker.RunsOnCreationTaskRunner(), false);
35 latch.Signal();
36 });
37 loop->Run();
38 });
39 latch.Wait();
40 loop->Terminate();
41 anotherThread.join();
42 EXPECT_EQ(checker.RunsOnCreationTaskRunner(), true);
43}
44
45TEST(TaskRunnerCheckerTests, SameTaskRunnerRunsOnTheSameThread) {
46 fml::MessageLoop& loop1 = fml::MessageLoop::GetCurrent();
47 fml::MessageLoop& loop2 = fml::MessageLoop::GetCurrent();
48 TaskQueueId a = loop1.GetTaskRunner()->GetTaskQueueId();
49 TaskQueueId b = loop2.GetTaskRunner()->GetTaskQueueId();
50 EXPECT_EQ(TaskRunnerChecker::RunsOnTheSameThread(a, b), true);
51}
52
53TEST(TaskRunnerCheckerTests, RunsOnDifferentThreadsReturnsFalse) {
54 fml::MessageLoop& loop1 = fml::MessageLoop::GetCurrent();
55 TaskQueueId a = loop1.GetTaskRunner()->GetTaskQueueId();
56 fml::AutoResetWaitableEvent latch;
57 std::thread anotherThread([&]() {
58 fml::MessageLoop::EnsureInitializedForCurrentThread();
59 fml::MessageLoop& loop2 = fml::MessageLoop::GetCurrent();
60 TaskQueueId b = loop2.GetTaskRunner()->GetTaskQueueId();
61 EXPECT_EQ(TaskRunnerChecker::RunsOnTheSameThread(a, b), false);
62 latch.Signal();
63 });
64 latch.Wait();
65 anotherThread.join();
66}
67
68TEST(TaskRunnerCheckerTests, MergedTaskRunnersRunsOnTheSameThread) {
69 fml::MessageLoop* loop1 = nullptr;
70 fml::AutoResetWaitableEvent latch1;
71 fml::AutoResetWaitableEvent term1;
72 std::thread thread1([&loop1, &latch1, &term1]() {
73 fml::MessageLoop::EnsureInitializedForCurrentThread();
74 loop1 = &fml::MessageLoop::GetCurrent();
75 latch1.Signal();
76 term1.Wait();
77 });
78
79 fml::MessageLoop* loop2 = nullptr;
80 fml::AutoResetWaitableEvent latch2;
81 fml::AutoResetWaitableEvent term2;
82 std::thread thread2([&loop2, &latch2, &term2]() {
83 fml::MessageLoop::EnsureInitializedForCurrentThread();
84 loop2 = &fml::MessageLoop::GetCurrent();
85 latch2.Signal();
86 term2.Wait();
87 });
88
89 latch1.Wait();
90 latch2.Wait();
91 fml::TaskQueueId qid1 = loop1->GetTaskRunner()->GetTaskQueueId();
92 fml::TaskQueueId qid2 = loop2->GetTaskRunner()->GetTaskQueueId();
93 const auto raster_thread_merger_ =
94 fml::MakeRefCounted<fml::RasterThreadMerger>(qid1, qid2);
95 const int kNumFramesMerged = 5;
96
97 raster_thread_merger_->MergeWithLease(kNumFramesMerged);
98
99 // merged, running on the same thread
100 EXPECT_EQ(TaskRunnerChecker::RunsOnTheSameThread(qid1, qid2), true);
101
102 for (int i = 0; i < kNumFramesMerged; i++) {
103 ASSERT_TRUE(raster_thread_merger_->IsMerged());
104 raster_thread_merger_->DecrementLease();
105 }
106
107 ASSERT_FALSE(raster_thread_merger_->IsMerged());
108
109 // un-merged, not running on the same thread
110 EXPECT_EQ(TaskRunnerChecker::RunsOnTheSameThread(qid1, qid2), false);
111
112 term1.Signal();
113 term2.Signal();
114 thread1.join();
115 thread2.join();
116}
117
118} // namespace testing
119} // namespace fml
120