Home | History | Annotate | Download | only in base
      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 {
     49   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 
     58   void Read() {
     59     char b;
     60     PERFETTO_DCHECK(read(read_fd.get(), &b, 1) == 1);
     61   }
     62 
     63   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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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>
    300 void RepeatingTask(TaskRunner* task_runner) {
    301   task_runner->PostTask(std::bind(&RepeatingTask<TaskRunner>, task_runner));
    302 }
    303 
    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>
    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 
    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 
    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 
    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