xref: /aosp_15_r20/external/perfetto/src/base/task_runner_unittest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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