Flutter Engine
The Flutter Engine
message_loop_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 "flutter/fml/message_loop.h"
8
9#include <iostream>
10#include <thread>
11
12#include "flutter/fml/build_config.h"
13#include "flutter/fml/concurrent_message_loop.h"
14#include "flutter/fml/synchronization/count_down_latch.h"
15#include "flutter/fml/synchronization/waitable_event.h"
16#include "flutter/fml/task_runner.h"
17#include "flutter/fml/time/chrono_timestamp_provider.h"
18#include "gtest/gtest.h"
19
20TEST(MessageLoop, GetCurrent) {
21 std::thread thread([]() {
23 ASSERT_TRUE(fml::MessageLoop::GetCurrent().GetTaskRunner());
24 });
25 thread.join();
26}
27
28TEST(MessageLoop, DifferentThreadsHaveDifferentLoops) {
29 fml::MessageLoop* loop1 = nullptr;
32 std::thread thread1([&loop1, &latch1, &term1]() {
35 latch1.Signal();
36 term1.Wait();
37 });
38
39 fml::MessageLoop* loop2 = nullptr;
42 std::thread thread2([&loop2, &latch2, &term2]() {
45 latch2.Signal();
46 term2.Wait();
47 });
48 latch1.Wait();
49 latch2.Wait();
50 ASSERT_FALSE(loop1 == loop2);
51 term1.Signal();
52 term2.Signal();
53 thread1.join();
54 thread2.join();
55}
56
57TEST(MessageLoop, CanRunAndTerminate) {
58 bool started = false;
59 bool terminated = false;
60 std::thread thread([&started, &terminated]() {
62 auto& loop = fml::MessageLoop::GetCurrent();
63 ASSERT_TRUE(loop.GetTaskRunner());
64 loop.GetTaskRunner()->PostTask([&terminated]() {
66 terminated = true;
67 });
68 loop.Run();
69 started = true;
70 });
71 thread.join();
72 ASSERT_TRUE(started);
73 ASSERT_TRUE(terminated);
74}
75
76TEST(MessageLoop, NonDelayedTasksAreRunInOrder) {
77 const size_t count = 100;
78 bool started = false;
79 bool terminated = false;
80 std::thread thread([&started, &terminated, count]() {
82 auto& loop = fml::MessageLoop::GetCurrent();
83 size_t current = 0;
84 for (size_t i = 0; i < count; i++) {
85 loop.GetTaskRunner()->PostTask([&terminated, i, &current]() {
86 ASSERT_EQ(current, i);
87 current++;
88 if (count == i + 1) {
90 terminated = true;
91 }
92 });
93 }
94 loop.Run();
95 ASSERT_EQ(current, count);
96 started = true;
97 });
98 thread.join();
99 ASSERT_TRUE(started);
100 ASSERT_TRUE(terminated);
101}
102
103TEST(MessageLoop, DelayedTasksAtSameTimeAreRunInOrder) {
104 const size_t count = 100;
105 bool started = false;
106 bool terminated = false;
107 std::thread thread([&started, &terminated, count]() {
109 auto& loop = fml::MessageLoop::GetCurrent();
110 size_t current = 0;
111 const auto now_plus_some =
113 for (size_t i = 0; i < count; i++) {
114 loop.GetTaskRunner()->PostTaskForTime(
115 [&terminated, i, &current]() {
116 ASSERT_EQ(current, i);
117 current++;
118 if (count == i + 1) {
120 terminated = true;
121 }
122 },
123 now_plus_some);
124 }
125 loop.Run();
126 ASSERT_EQ(current, count);
127 started = true;
128 });
129 thread.join();
130 ASSERT_TRUE(started);
131 ASSERT_TRUE(terminated);
132}
133
134TEST(MessageLoop, CheckRunsTaskOnCurrentThread) {
137 std::thread thread([&runner, &latch]() {
139 auto& loop = fml::MessageLoop::GetCurrent();
140 runner = loop.GetTaskRunner();
141 latch.Signal();
142 ASSERT_TRUE(loop.GetTaskRunner()->RunsTasksOnCurrentThread());
143 });
144 latch.Wait();
145 ASSERT_TRUE(runner);
146 ASSERT_FALSE(runner->RunsTasksOnCurrentThread());
147 thread.join();
148}
149
150TEST(MessageLoop, TaskObserverFire) {
151 bool started = false;
152 bool terminated = false;
153 std::thread thread([&started, &terminated]() {
155 const size_t count = 25;
156 auto& loop = fml::MessageLoop::GetCurrent();
157 size_t task_count = 0;
158 size_t obs_count = 0;
159 auto obs = [&obs_count]() { obs_count++; };
160 for (size_t i = 0; i < count; i++) {
161 loop.GetTaskRunner()->PostTask([&terminated, i, &task_count]() {
162 ASSERT_EQ(task_count, i);
163 task_count++;
164 if (count == i + 1) {
166 terminated = true;
167 }
168 });
169 }
170 loop.AddTaskObserver(0, obs);
171 loop.Run();
172 ASSERT_EQ(task_count, count);
173 ASSERT_EQ(obs_count, count);
174 started = true;
175 });
176 thread.join();
177 ASSERT_TRUE(started);
178 ASSERT_TRUE(terminated);
179}
180
181TEST(MessageLoop, ConcurrentMessageLoopHasNonZeroWorkers) {
183 0u /* explicitly specify zero workers */);
184 ASSERT_GT(loop->GetWorkerCount(), 0u);
185}
186
187TEST(MessageLoop, CanCreateAndShutdownConcurrentMessageLoopsOverAndOver) {
188 for (size_t i = 0; i < 10; ++i) {
189 auto loop = fml::ConcurrentMessageLoop::Create(i + 1);
190 ASSERT_EQ(loop->GetWorkerCount(), i + 1);
191 }
192}
193
194TEST(MessageLoop, CanCreateConcurrentMessageLoop) {
196 auto task_runner = loop->GetTaskRunner();
197 const size_t kCount = 10;
198 fml::CountDownLatch latch(kCount);
199 std::mutex thread_ids_mutex;
200 std::set<std::thread::id> thread_ids;
201 for (size_t i = 0; i < kCount; ++i) {
202 task_runner->PostTask([&]() {
203 std::this_thread::sleep_for(std::chrono::seconds(1));
204 std::cout << "Ran on thread: " << std::this_thread::get_id() << std::endl;
205 {
206 std::scoped_lock lock(thread_ids_mutex);
207 thread_ids.insert(std::this_thread::get_id());
208 }
209 latch.CountDown();
210 });
211 }
212 latch.Wait();
213 ASSERT_GE(thread_ids.size(), 1u);
214}
int count
Definition: FontMgrTest.cpp:50
static void loop1(skiatest::Reporter *reporter, const char *filename)
static void loop2(skiatest::Reporter *reporter, const char *filename)
static std::shared_ptr< ConcurrentMessageLoop > Create(size_t worker_count=std::thread::hardware_concurrency())
static void EnsureInitializedForCurrentThread()
Definition: message_loop.cc:27
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
Definition: message_loop.cc:19
virtual bool RunsTasksOnCurrentThread()
Definition: task_runner.cc:43
static constexpr TimeDelta FromMilliseconds(int64_t millis)
Definition: time_delta.h:46
TEST(MessageLoop, GetCurrent)
fml::TimePoint ChronoTicksSinceEpoch()