• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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