• 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_CHROMIUM_BUILD)
25 #include "perfetto/base/android_task_runner.h"
26 #endif
27 
28 #include <thread>
29 
30 namespace perfetto {
31 namespace base {
32 namespace {
33 
34 template <typename T>
35 class TaskRunnerTest : public ::testing::Test {
36  public:
37   T task_runner;
38 };
39 
40 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
41     !PERFETTO_BUILDFLAG(PERFETTO_CHROMIUM_BUILD)
42 using TaskRunnerTypes = ::testing::Types<AndroidTaskRunner, UnixTaskRunner>;
43 #else
44 using TaskRunnerTypes = ::testing::Types<UnixTaskRunner>;
45 #endif
46 TYPED_TEST_CASE(TaskRunnerTest, TaskRunnerTypes);
47 
48 struct Pipe {
Pipeperfetto::base::__anon449ea1060111::Pipe49   Pipe() {
50     int pipe_fds[2];
51     PERFETTO_DCHECK(pipe(pipe_fds) == 0);
52     read_fd.reset(pipe_fds[0]);
53     write_fd.reset(pipe_fds[1]);
54     // Make the pipe initially readable.
55     Write();
56   }
57 
Readperfetto::base::__anon449ea1060111::Pipe58   void Read() {
59     char b;
60     PERFETTO_DCHECK(read(read_fd.get(), &b, 1) == 1);
61   }
62 
Writeperfetto::base::__anon449ea1060111::Pipe63   void Write() {
64     const char b = '?';
65     PERFETTO_DCHECK(write(write_fd.get(), &b, 1) == 1);
66   }
67 
68   ScopedFile read_fd;
69   ScopedFile write_fd;
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   Pipe pipe;
143   task_runner.AddFileDescriptorWatch(pipe.read_fd.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   Pipe pipe;
151 
152   bool watch_ran = false;
153   task_runner.AddFileDescriptorWatch(pipe.read_fd.get(),
154                                      [&watch_ran] { watch_ran = true; });
155   task_runner.RemoveFileDescriptorWatch(pipe.read_fd.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   Pipe pipe;
165 
166   bool watch_ran = false;
167   task_runner.PostTask([&task_runner, &pipe] {
168     task_runner.RemoveFileDescriptorWatch(pipe.read_fd.get());
169   });
170   task_runner.AddFileDescriptorWatch(pipe.read_fd.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   Pipe pipe;
181   Pipe pipe2;
182 
183   task_runner.AddFileDescriptorWatch(
184       pipe.read_fd.get(), [&task_runner, &pipe, &pipe2] {
185         pipe.Read();
186         task_runner.AddFileDescriptorWatch(
187             pipe2.read_fd.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   Pipe pipe;
195   Pipe pipe2;
196 
197   bool watch_ran = false;
198   task_runner.AddFileDescriptorWatch(
199       pipe.read_fd.get(), [&task_runner, &pipe, &pipe2] {
200         pipe.Read();
201         task_runner.RemoveFileDescriptorWatch(pipe2.read_fd.get());
202       });
203   task_runner.AddFileDescriptorWatch(pipe2.read_fd.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   Pipe pipe;
214   Pipe pipe2;
215 
216   bool watch_ran = false;
217   task_runner.AddFileDescriptorWatch(
218       pipe.read_fd.get(), [&task_runner, &pipe2] {
219         task_runner.RemoveFileDescriptorWatch(pipe2.read_fd.get());
220         task_runner.AddFileDescriptorWatch(
221             pipe2.read_fd.get(), [&task_runner] { task_runner.Quit(); });
222       });
223   task_runner.AddFileDescriptorWatch(pipe2.read_fd.get(),
224                                      [&watch_ran] { watch_ran = true; });
225   task_runner.Run();
226 
227   EXPECT_FALSE(watch_ran);
228 }
229 
TYPED_TEST(TaskRunnerTest,AddFileDescriptorWatchFromAnotherThread)230 TYPED_TEST(TaskRunnerTest, AddFileDescriptorWatchFromAnotherThread) {
231   auto& task_runner = this->task_runner;
232   Pipe pipe;
233 
234   std::thread thread([&task_runner, &pipe] {
235     task_runner.AddFileDescriptorWatch(pipe.read_fd.get(),
236                                        [&task_runner] { task_runner.Quit(); });
237   });
238   task_runner.Run();
239   thread.join();
240 }
241 
TYPED_TEST(TaskRunnerTest,FileDescriptorWatchWithMultipleEvents)242 TYPED_TEST(TaskRunnerTest, FileDescriptorWatchWithMultipleEvents) {
243   auto& task_runner = this->task_runner;
244   Pipe pipe;
245 
246   int event_count = 0;
247   task_runner.AddFileDescriptorWatch(pipe.read_fd.get(),
248                                      [&task_runner, &pipe, &event_count] {
249                                        if (++event_count == 3) {
250                                          task_runner.Quit();
251                                          return;
252                                        }
253                                        pipe.Read();
254                                      });
255   task_runner.PostTask([&pipe] { pipe.Write(); });
256   task_runner.PostTask([&pipe] { pipe.Write(); });
257   task_runner.Run();
258 }
259 
TYPED_TEST(TaskRunnerTest,FileDescriptorClosedEvent)260 TYPED_TEST(TaskRunnerTest, FileDescriptorClosedEvent) {
261   auto& task_runner = this->task_runner;
262   int pipe_fds[2];
263   PERFETTO_DCHECK(pipe(pipe_fds) == 0);
264   ScopedFile read_fd(pipe_fds[0]);
265   ScopedFile write_fd(pipe_fds[1]);
266 
267   write_fd.reset();
268   task_runner.AddFileDescriptorWatch(read_fd.get(),
269                                      [&task_runner] { task_runner.Quit(); });
270   task_runner.Run();
271 }
272 
TYPED_TEST(TaskRunnerTest,PostManyDelayedTasks)273 TYPED_TEST(TaskRunnerTest, PostManyDelayedTasks) {
274   // Check that PostTask doesn't start failing if there are too many scheduled
275   // wake-ups.
276   auto& task_runner = this->task_runner;
277   for (int i = 0; i < 0x1000; i++)
278     task_runner.PostDelayedTask([] {}, 0);
279   task_runner.PostDelayedTask([&task_runner] { task_runner.Quit(); }, 10);
280   task_runner.Run();
281 }
282 
TYPED_TEST(TaskRunnerTest,RunAgain)283 TYPED_TEST(TaskRunnerTest, RunAgain) {
284   auto& task_runner = this->task_runner;
285   int counter = 0;
286   task_runner.PostTask([&task_runner, &counter] {
287     counter++;
288     task_runner.Quit();
289   });
290   task_runner.Run();
291   task_runner.PostTask([&task_runner, &counter] {
292     counter++;
293     task_runner.Quit();
294   });
295   task_runner.Run();
296   EXPECT_EQ(2, counter);
297 }
298 
299 template <typename TaskRunner>
RepeatingTask(TaskRunner * task_runner)300 void RepeatingTask(TaskRunner* task_runner) {
301   task_runner->PostTask(std::bind(&RepeatingTask<TaskRunner>, task_runner));
302 }
303 
TYPED_TEST(TaskRunnerTest,FileDescriptorWatchesNotStarved)304 TYPED_TEST(TaskRunnerTest, FileDescriptorWatchesNotStarved) {
305   auto& task_runner = this->task_runner;
306   Pipe pipe;
307   task_runner.PostTask(std::bind(&RepeatingTask<TypeParam>, &task_runner));
308   task_runner.AddFileDescriptorWatch(pipe.read_fd.get(),
309                                      [&task_runner] { task_runner.Quit(); });
310   task_runner.Run();
311 }
312 
313 template <typename TaskRunner>
CountdownTask(TaskRunner * task_runner,int * counter)314 void CountdownTask(TaskRunner* task_runner, int* counter) {
315   if (!--(*counter)) {
316     task_runner->Quit();
317     return;
318   }
319   task_runner->PostTask(
320       std::bind(&CountdownTask<TaskRunner>, task_runner, counter));
321 }
322 
TYPED_TEST(TaskRunnerTest,NoDuplicateFileDescriptorWatchCallbacks)323 TYPED_TEST(TaskRunnerTest, NoDuplicateFileDescriptorWatchCallbacks) {
324   auto& task_runner = this->task_runner;
325   Pipe pipe;
326   bool watch_called = 0;
327   int counter = 10;
328   task_runner.AddFileDescriptorWatch(pipe.read_fd.get(),
329                                      [&pipe, &watch_called] {
330                                        ASSERT_FALSE(watch_called);
331                                        pipe.Read();
332                                        watch_called = true;
333                                      });
334   task_runner.PostTask(
335       std::bind(&CountdownTask<TypeParam>, &task_runner, &counter));
336   task_runner.Run();
337 }
338 
TYPED_TEST(TaskRunnerTest,ReplaceFileDescriptorWatchFromOtherThread)339 TYPED_TEST(TaskRunnerTest, ReplaceFileDescriptorWatchFromOtherThread) {
340   auto& task_runner = this->task_runner;
341   Pipe pipe;
342 
343   // The two watch tasks here race each other. We don't particularly care which
344   // wins as long as one of them runs.
345   task_runner.AddFileDescriptorWatch(pipe.read_fd.get(),
346                                      [&task_runner] { task_runner.Quit(); });
347 
348   std::thread thread([&task_runner, &pipe] {
349     task_runner.RemoveFileDescriptorWatch(pipe.read_fd.get());
350     task_runner.AddFileDescriptorWatch(pipe.read_fd.get(),
351                                        [&task_runner] { task_runner.Quit(); });
352   });
353 
354   task_runner.Run();
355   thread.join();
356 }
357 
TYPED_TEST(TaskRunnerTest,IsIdleForTesting)358 TYPED_TEST(TaskRunnerTest, IsIdleForTesting) {
359   auto& task_runner = this->task_runner;
360   task_runner.PostTask(
361       [&task_runner] { EXPECT_FALSE(task_runner.IsIdleForTesting()); });
362   task_runner.PostTask([&task_runner] {
363     EXPECT_TRUE(task_runner.IsIdleForTesting());
364     task_runner.Quit();
365   });
366   task_runner.Run();
367 }
368 
369 }  // namespace
370 }  // namespace base
371 }  // namespace perfetto
372