Home | History | Annotate | Download | only in simpleperf
      1 /*
      2  * Copyright (C) 2016 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 "IOEventLoop.h"
     18 
     19 #include <gtest/gtest.h>
     20 
     21 #include <atomic>
     22 #include <chrono>
     23 #include <thread>
     24 
     25 TEST(IOEventLoop, read) {
     26   int fd[2];
     27   ASSERT_EQ(0, pipe(fd));
     28   IOEventLoop loop;
     29   int count = 0;
     30   int retry_count = 0;
     31   ASSERT_NE(nullptr, loop.AddReadEvent(fd[0], [&]() {
     32     while (true) {
     33       char c;
     34       int ret = read(fd[0], &c, 1);
     35       if (ret == 1) {
     36         if (++count == 100) {
     37           return loop.ExitLoop();
     38         }
     39       } else if (ret == -1 && errno == EAGAIN) {
     40         retry_count++;
     41         break;
     42       } else {
     43         return false;
     44       }
     45     }
     46     return true;
     47   }));
     48   std::thread thread([&]() {
     49     for (int i = 0; i < 100; ++i) {
     50       usleep(1000);
     51       char c;
     52       write(fd[1], &c, 1);
     53     }
     54   });
     55   ASSERT_TRUE(loop.RunLoop());
     56   thread.join();
     57   ASSERT_EQ(100, count);
     58   // Test retry_count to make sure we are not doing blocking read.
     59   ASSERT_GT(retry_count, 0);
     60   close(fd[0]);
     61   close(fd[1]);
     62 }
     63 
     64 TEST(IOEventLoop, write) {
     65   int fd[2];
     66   ASSERT_EQ(0, pipe(fd));
     67   IOEventLoop loop;
     68   int count = 0;
     69   ASSERT_NE(nullptr, loop.AddWriteEvent(fd[1], [&]() {
     70     int ret = 0;
     71     char buf[4096];
     72     while ((ret = write(fd[1], buf, sizeof(buf))) > 0) {
     73     }
     74     if (ret == -1 && errno == EAGAIN) {
     75       if (++count == 100) {
     76         loop.ExitLoop();
     77       }
     78       return true;
     79     }
     80     return false;
     81   }));
     82   std::thread thread([&]() {
     83     usleep(500000);
     84     while (true) {
     85       usleep(1000);
     86       char buf[4096];
     87       if (read(fd[0], buf, sizeof(buf)) <= 0) {
     88         break;
     89       }
     90     }
     91   });
     92   ASSERT_TRUE(loop.RunLoop());
     93   // close fd[1] to make read thread stop.
     94   close(fd[1]);
     95   thread.join();
     96   close(fd[0]);
     97   ASSERT_EQ(100, count);
     98 }
     99 
    100 TEST(IOEventLoop, signal) {
    101   IOEventLoop loop;
    102   int count = 0;
    103   ASSERT_TRUE(loop.AddSignalEvent(SIGINT, [&]() {
    104     if (++count == 100) {
    105       loop.ExitLoop();
    106     }
    107     return true;
    108   }));
    109   std::atomic<bool> stop_thread(false);
    110   std::thread thread([&]() {
    111     while (!stop_thread) {
    112       usleep(1000);
    113       kill(getpid(), SIGINT);
    114     }
    115   });
    116   ASSERT_TRUE(loop.RunLoop());
    117   stop_thread = true;
    118   thread.join();
    119   ASSERT_EQ(100, count);
    120 }
    121 
    122 TEST(IOEventLoop, periodic) {
    123   timeval tv;
    124   tv.tv_sec = 0;
    125   tv.tv_usec = 1000;
    126   int count = 0;
    127   IOEventLoop loop;
    128   ASSERT_TRUE(loop.AddPeriodicEvent(tv, [&]() {
    129     if (++count == 100) {
    130       loop.ExitLoop();
    131     }
    132     return true;
    133   }));
    134   auto start_time = std::chrono::steady_clock::now();
    135   ASSERT_TRUE(loop.RunLoop());
    136   auto end_time = std::chrono::steady_clock::now();
    137   ASSERT_EQ(100, count);
    138   double time_used = std::chrono::duration_cast<std::chrono::duration<double>>(
    139                          end_time - start_time)
    140                          .count();
    141   // time_used is 0.1 if running precisely, and we accept small errors by using
    142   // a range [0.1, 0.15).
    143   ASSERT_GE(time_used, 0.1);
    144   ASSERT_LT(time_used, 0.15);
    145 }
    146 
    147 TEST(IOEventLoop, read_and_del_event) {
    148   int fd[2];
    149   ASSERT_EQ(0, pipe(fd));
    150   IOEventLoop loop;
    151   int count = 0;
    152   IOEventRef ref = loop.AddReadEvent(fd[0], [&]() {
    153     count++;
    154     return IOEventLoop::DelEvent(ref);
    155   });
    156   ASSERT_NE(nullptr, ref);
    157 
    158   std::thread thread([&]() {
    159     for (int i = 0; i < 100; ++i) {
    160       usleep(1000);
    161       char c;
    162       write(fd[1], &c, 1);
    163     }
    164   });
    165   ASSERT_TRUE(loop.RunLoop());
    166   thread.join();
    167   ASSERT_EQ(1, count);
    168   close(fd[0]);
    169   close(fd[1]);
    170 }
    171 
    172 TEST(IOEventLoop, disable_enable_event) {
    173   int fd[2];
    174   ASSERT_EQ(0, pipe(fd));
    175   IOEventLoop loop;
    176   int count = 0;
    177   IOEventRef ref = loop.AddWriteEvent(fd[1], [&]() {
    178     count++;
    179     return IOEventLoop::DisableEvent(ref);
    180   });
    181   ASSERT_NE(nullptr, ref);
    182 
    183   timeval tv;
    184   tv.tv_sec = 0;
    185   tv.tv_usec = 500000;
    186   int periodic_count = 0;
    187   ASSERT_TRUE(loop.AddPeriodicEvent(tv, [&]() {
    188     periodic_count++;
    189     if (periodic_count == 1) {
    190       if (count != 1) {
    191         return false;
    192       }
    193       return IOEventLoop::EnableEvent(ref);
    194     } else {
    195       if (count != 2) {
    196         return false;
    197       }
    198       return loop.ExitLoop();
    199     }
    200   }));
    201 
    202   ASSERT_TRUE(loop.RunLoop());
    203   ASSERT_EQ(2, count);
    204   ASSERT_EQ(2, periodic_count);
    205   close(fd[0]);
    206   close(fd[1]);
    207 }
    208