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