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