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