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