1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "perfetto/base/unix_task_runner.h"
18
19 #include "gtest/gtest.h"
20 #include "perfetto/base/build_config.h"
21 #include "perfetto/base/scoped_file.h"
22
23 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
24 !PERFETTO_BUILDFLAG(PERFETTO_CHROMIUM_BUILD)
25 #include "perfetto/base/android_task_runner.h"
26 #endif
27
28 #include <thread>
29
30 namespace perfetto {
31 namespace base {
32 namespace {
33
34 template <typename T>
35 class TaskRunnerTest : public ::testing::Test {
36 public:
37 T task_runner;
38 };
39
40 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
41 !PERFETTO_BUILDFLAG(PERFETTO_CHROMIUM_BUILD)
42 using TaskRunnerTypes = ::testing::Types<AndroidTaskRunner, UnixTaskRunner>;
43 #else
44 using TaskRunnerTypes = ::testing::Types<UnixTaskRunner>;
45 #endif
46 TYPED_TEST_CASE(TaskRunnerTest, TaskRunnerTypes);
47
48 struct Pipe {
Pipeperfetto::base::__anon449ea1060111::Pipe49 Pipe() {
50 int pipe_fds[2];
51 PERFETTO_DCHECK(pipe(pipe_fds) == 0);
52 read_fd.reset(pipe_fds[0]);
53 write_fd.reset(pipe_fds[1]);
54 // Make the pipe initially readable.
55 Write();
56 }
57
Readperfetto::base::__anon449ea1060111::Pipe58 void Read() {
59 char b;
60 PERFETTO_DCHECK(read(read_fd.get(), &b, 1) == 1);
61 }
62
Writeperfetto::base::__anon449ea1060111::Pipe63 void Write() {
64 const char b = '?';
65 PERFETTO_DCHECK(write(write_fd.get(), &b, 1) == 1);
66 }
67
68 ScopedFile read_fd;
69 ScopedFile write_fd;
70 };
71
TYPED_TEST(TaskRunnerTest,PostImmediateTask)72 TYPED_TEST(TaskRunnerTest, PostImmediateTask) {
73 auto& task_runner = this->task_runner;
74 int counter = 0;
75 task_runner.PostTask([&counter] { counter = (counter << 4) | 1; });
76 task_runner.PostTask([&counter] { counter = (counter << 4) | 2; });
77 task_runner.PostTask([&counter] { counter = (counter << 4) | 3; });
78 task_runner.PostTask([&counter] { counter = (counter << 4) | 4; });
79 task_runner.PostTask([&task_runner] { task_runner.Quit(); });
80 task_runner.Run();
81 EXPECT_EQ(0x1234, counter);
82 }
83
TYPED_TEST(TaskRunnerTest,PostDelayedTask)84 TYPED_TEST(TaskRunnerTest, PostDelayedTask) {
85 auto& task_runner = this->task_runner;
86 int counter = 0;
87 task_runner.PostDelayedTask([&counter] { counter = (counter << 4) | 1; }, 5);
88 task_runner.PostDelayedTask([&counter] { counter = (counter << 4) | 2; }, 10);
89 task_runner.PostDelayedTask([&counter] { counter = (counter << 4) | 3; }, 15);
90 task_runner.PostDelayedTask([&counter] { counter = (counter << 4) | 4; }, 15);
91 task_runner.PostDelayedTask([&task_runner] { task_runner.Quit(); }, 20);
92 task_runner.Run();
93 EXPECT_EQ(0x1234, counter);
94 }
95
TYPED_TEST(TaskRunnerTest,PostImmediateTaskFromTask)96 TYPED_TEST(TaskRunnerTest, PostImmediateTaskFromTask) {
97 auto& task_runner = this->task_runner;
98 task_runner.PostTask([&task_runner] {
99 task_runner.PostTask([&task_runner] { task_runner.Quit(); });
100 });
101 task_runner.Run();
102 }
103
TYPED_TEST(TaskRunnerTest,PostDelayedTaskFromTask)104 TYPED_TEST(TaskRunnerTest, PostDelayedTaskFromTask) {
105 auto& task_runner = this->task_runner;
106 task_runner.PostTask([&task_runner] {
107 task_runner.PostDelayedTask([&task_runner] { task_runner.Quit(); }, 10);
108 });
109 task_runner.Run();
110 }
111
TYPED_TEST(TaskRunnerTest,PostImmediateTaskFromOtherThread)112 TYPED_TEST(TaskRunnerTest, PostImmediateTaskFromOtherThread) {
113 auto& task_runner = this->task_runner;
114 ThreadChecker thread_checker;
115 int counter = 0;
116 std::thread thread([&task_runner, &counter, &thread_checker] {
117 task_runner.PostTask([&thread_checker] {
118 EXPECT_TRUE(thread_checker.CalledOnValidThread());
119 });
120 task_runner.PostTask([&counter] { counter = (counter << 4) | 1; });
121 task_runner.PostTask([&counter] { counter = (counter << 4) | 2; });
122 task_runner.PostTask([&counter] { counter = (counter << 4) | 3; });
123 task_runner.PostTask([&counter] { counter = (counter << 4) | 4; });
124 task_runner.PostTask([&task_runner] { task_runner.Quit(); });
125 });
126 task_runner.Run();
127 thread.join();
128 EXPECT_EQ(0x1234, counter);
129 }
130
TYPED_TEST(TaskRunnerTest,PostDelayedTaskFromOtherThread)131 TYPED_TEST(TaskRunnerTest, PostDelayedTaskFromOtherThread) {
132 auto& task_runner = this->task_runner;
133 std::thread thread([&task_runner] {
134 task_runner.PostDelayedTask([&task_runner] { task_runner.Quit(); }, 10);
135 });
136 task_runner.Run();
137 thread.join();
138 }
139
TYPED_TEST(TaskRunnerTest,AddFileDescriptorWatch)140 TYPED_TEST(TaskRunnerTest, AddFileDescriptorWatch) {
141 auto& task_runner = this->task_runner;
142 Pipe pipe;
143 task_runner.AddFileDescriptorWatch(pipe.read_fd.get(),
144 [&task_runner] { task_runner.Quit(); });
145 task_runner.Run();
146 }
147
TYPED_TEST(TaskRunnerTest,RemoveFileDescriptorWatch)148 TYPED_TEST(TaskRunnerTest, RemoveFileDescriptorWatch) {
149 auto& task_runner = this->task_runner;
150 Pipe pipe;
151
152 bool watch_ran = false;
153 task_runner.AddFileDescriptorWatch(pipe.read_fd.get(),
154 [&watch_ran] { watch_ran = true; });
155 task_runner.RemoveFileDescriptorWatch(pipe.read_fd.get());
156 task_runner.PostDelayedTask([&task_runner] { task_runner.Quit(); }, 10);
157 task_runner.Run();
158
159 EXPECT_FALSE(watch_ran);
160 }
161
TYPED_TEST(TaskRunnerTest,RemoveFileDescriptorWatchFromTask)162 TYPED_TEST(TaskRunnerTest, RemoveFileDescriptorWatchFromTask) {
163 auto& task_runner = this->task_runner;
164 Pipe pipe;
165
166 bool watch_ran = false;
167 task_runner.PostTask([&task_runner, &pipe] {
168 task_runner.RemoveFileDescriptorWatch(pipe.read_fd.get());
169 });
170 task_runner.AddFileDescriptorWatch(pipe.read_fd.get(),
171 [&watch_ran] { watch_ran = true; });
172 task_runner.PostDelayedTask([&task_runner] { task_runner.Quit(); }, 10);
173 task_runner.Run();
174
175 EXPECT_FALSE(watch_ran);
176 }
177
TYPED_TEST(TaskRunnerTest,AddFileDescriptorWatchFromAnotherWatch)178 TYPED_TEST(TaskRunnerTest, AddFileDescriptorWatchFromAnotherWatch) {
179 auto& task_runner = this->task_runner;
180 Pipe pipe;
181 Pipe pipe2;
182
183 task_runner.AddFileDescriptorWatch(
184 pipe.read_fd.get(), [&task_runner, &pipe, &pipe2] {
185 pipe.Read();
186 task_runner.AddFileDescriptorWatch(
187 pipe2.read_fd.get(), [&task_runner] { task_runner.Quit(); });
188 });
189 task_runner.Run();
190 }
191
TYPED_TEST(TaskRunnerTest,RemoveFileDescriptorWatchFromAnotherWatch)192 TYPED_TEST(TaskRunnerTest, RemoveFileDescriptorWatchFromAnotherWatch) {
193 auto& task_runner = this->task_runner;
194 Pipe pipe;
195 Pipe pipe2;
196
197 bool watch_ran = false;
198 task_runner.AddFileDescriptorWatch(
199 pipe.read_fd.get(), [&task_runner, &pipe, &pipe2] {
200 pipe.Read();
201 task_runner.RemoveFileDescriptorWatch(pipe2.read_fd.get());
202 });
203 task_runner.AddFileDescriptorWatch(pipe2.read_fd.get(),
204 [&watch_ran] { watch_ran = true; });
205 task_runner.PostDelayedTask([&task_runner] { task_runner.Quit(); }, 10);
206 task_runner.Run();
207
208 EXPECT_FALSE(watch_ran);
209 }
210
TYPED_TEST(TaskRunnerTest,ReplaceFileDescriptorWatchFromAnotherWatch)211 TYPED_TEST(TaskRunnerTest, ReplaceFileDescriptorWatchFromAnotherWatch) {
212 auto& task_runner = this->task_runner;
213 Pipe pipe;
214 Pipe pipe2;
215
216 bool watch_ran = false;
217 task_runner.AddFileDescriptorWatch(
218 pipe.read_fd.get(), [&task_runner, &pipe2] {
219 task_runner.RemoveFileDescriptorWatch(pipe2.read_fd.get());
220 task_runner.AddFileDescriptorWatch(
221 pipe2.read_fd.get(), [&task_runner] { task_runner.Quit(); });
222 });
223 task_runner.AddFileDescriptorWatch(pipe2.read_fd.get(),
224 [&watch_ran] { watch_ran = true; });
225 task_runner.Run();
226
227 EXPECT_FALSE(watch_ran);
228 }
229
TYPED_TEST(TaskRunnerTest,AddFileDescriptorWatchFromAnotherThread)230 TYPED_TEST(TaskRunnerTest, AddFileDescriptorWatchFromAnotherThread) {
231 auto& task_runner = this->task_runner;
232 Pipe pipe;
233
234 std::thread thread([&task_runner, &pipe] {
235 task_runner.AddFileDescriptorWatch(pipe.read_fd.get(),
236 [&task_runner] { task_runner.Quit(); });
237 });
238 task_runner.Run();
239 thread.join();
240 }
241
TYPED_TEST(TaskRunnerTest,FileDescriptorWatchWithMultipleEvents)242 TYPED_TEST(TaskRunnerTest, FileDescriptorWatchWithMultipleEvents) {
243 auto& task_runner = this->task_runner;
244 Pipe pipe;
245
246 int event_count = 0;
247 task_runner.AddFileDescriptorWatch(pipe.read_fd.get(),
248 [&task_runner, &pipe, &event_count] {
249 if (++event_count == 3) {
250 task_runner.Quit();
251 return;
252 }
253 pipe.Read();
254 });
255 task_runner.PostTask([&pipe] { pipe.Write(); });
256 task_runner.PostTask([&pipe] { pipe.Write(); });
257 task_runner.Run();
258 }
259
TYPED_TEST(TaskRunnerTest,FileDescriptorClosedEvent)260 TYPED_TEST(TaskRunnerTest, FileDescriptorClosedEvent) {
261 auto& task_runner = this->task_runner;
262 int pipe_fds[2];
263 PERFETTO_DCHECK(pipe(pipe_fds) == 0);
264 ScopedFile read_fd(pipe_fds[0]);
265 ScopedFile write_fd(pipe_fds[1]);
266
267 write_fd.reset();
268 task_runner.AddFileDescriptorWatch(read_fd.get(),
269 [&task_runner] { task_runner.Quit(); });
270 task_runner.Run();
271 }
272
TYPED_TEST(TaskRunnerTest,PostManyDelayedTasks)273 TYPED_TEST(TaskRunnerTest, PostManyDelayedTasks) {
274 // Check that PostTask doesn't start failing if there are too many scheduled
275 // wake-ups.
276 auto& task_runner = this->task_runner;
277 for (int i = 0; i < 0x1000; i++)
278 task_runner.PostDelayedTask([] {}, 0);
279 task_runner.PostDelayedTask([&task_runner] { task_runner.Quit(); }, 10);
280 task_runner.Run();
281 }
282
TYPED_TEST(TaskRunnerTest,RunAgain)283 TYPED_TEST(TaskRunnerTest, RunAgain) {
284 auto& task_runner = this->task_runner;
285 int counter = 0;
286 task_runner.PostTask([&task_runner, &counter] {
287 counter++;
288 task_runner.Quit();
289 });
290 task_runner.Run();
291 task_runner.PostTask([&task_runner, &counter] {
292 counter++;
293 task_runner.Quit();
294 });
295 task_runner.Run();
296 EXPECT_EQ(2, counter);
297 }
298
299 template <typename TaskRunner>
RepeatingTask(TaskRunner * task_runner)300 void RepeatingTask(TaskRunner* task_runner) {
301 task_runner->PostTask(std::bind(&RepeatingTask<TaskRunner>, task_runner));
302 }
303
TYPED_TEST(TaskRunnerTest,FileDescriptorWatchesNotStarved)304 TYPED_TEST(TaskRunnerTest, FileDescriptorWatchesNotStarved) {
305 auto& task_runner = this->task_runner;
306 Pipe pipe;
307 task_runner.PostTask(std::bind(&RepeatingTask<TypeParam>, &task_runner));
308 task_runner.AddFileDescriptorWatch(pipe.read_fd.get(),
309 [&task_runner] { task_runner.Quit(); });
310 task_runner.Run();
311 }
312
313 template <typename TaskRunner>
CountdownTask(TaskRunner * task_runner,int * counter)314 void CountdownTask(TaskRunner* task_runner, int* counter) {
315 if (!--(*counter)) {
316 task_runner->Quit();
317 return;
318 }
319 task_runner->PostTask(
320 std::bind(&CountdownTask<TaskRunner>, task_runner, counter));
321 }
322
TYPED_TEST(TaskRunnerTest,NoDuplicateFileDescriptorWatchCallbacks)323 TYPED_TEST(TaskRunnerTest, NoDuplicateFileDescriptorWatchCallbacks) {
324 auto& task_runner = this->task_runner;
325 Pipe pipe;
326 bool watch_called = 0;
327 int counter = 10;
328 task_runner.AddFileDescriptorWatch(pipe.read_fd.get(),
329 [&pipe, &watch_called] {
330 ASSERT_FALSE(watch_called);
331 pipe.Read();
332 watch_called = true;
333 });
334 task_runner.PostTask(
335 std::bind(&CountdownTask<TypeParam>, &task_runner, &counter));
336 task_runner.Run();
337 }
338
TYPED_TEST(TaskRunnerTest,ReplaceFileDescriptorWatchFromOtherThread)339 TYPED_TEST(TaskRunnerTest, ReplaceFileDescriptorWatchFromOtherThread) {
340 auto& task_runner = this->task_runner;
341 Pipe pipe;
342
343 // The two watch tasks here race each other. We don't particularly care which
344 // wins as long as one of them runs.
345 task_runner.AddFileDescriptorWatch(pipe.read_fd.get(),
346 [&task_runner] { task_runner.Quit(); });
347
348 std::thread thread([&task_runner, &pipe] {
349 task_runner.RemoveFileDescriptorWatch(pipe.read_fd.get());
350 task_runner.AddFileDescriptorWatch(pipe.read_fd.get(),
351 [&task_runner] { task_runner.Quit(); });
352 });
353
354 task_runner.Run();
355 thread.join();
356 }
357
TYPED_TEST(TaskRunnerTest,IsIdleForTesting)358 TYPED_TEST(TaskRunnerTest, IsIdleForTesting) {
359 auto& task_runner = this->task_runner;
360 task_runner.PostTask(
361 [&task_runner] { EXPECT_FALSE(task_runner.IsIdleForTesting()); });
362 task_runner.PostTask([&task_runner] {
363 EXPECT_TRUE(task_runner.IsIdleForTesting());
364 task_runner.Quit();
365 });
366 task_runner.Run();
367 }
368
369 } // namespace
370 } // namespace base
371 } // namespace perfetto
372