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