• 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/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