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 void TestPeriodicEvents(int period_in_us, int iterations, bool precise) { 123 timeval tv; 124 tv.tv_sec = period_in_us / 1000000; 125 tv.tv_usec = period_in_us % 1000000; 126 int count = 0; 127 IOEventLoop loop; 128 if (precise) { 129 ASSERT_TRUE(loop.UsePreciseTimer()); 130 } 131 ASSERT_TRUE(loop.AddPeriodicEvent(tv, [&]() { 132 if (++count == iterations) { 133 loop.ExitLoop(); 134 } 135 return true; 136 })); 137 auto start_time = std::chrono::steady_clock::now(); 138 ASSERT_TRUE(loop.RunLoop()); 139 auto end_time = std::chrono::steady_clock::now(); 140 ASSERT_EQ(iterations, count); 141 double time_used = std::chrono::duration_cast<std::chrono::duration<double>>( 142 end_time - start_time).count(); 143 double min_time_in_sec = period_in_us / 1e6 * iterations; 144 double max_time_in_sec = min_time_in_sec + (precise ? 0.1 : 1); 145 ASSERT_GE(time_used, min_time_in_sec); 146 ASSERT_LT(time_used, max_time_in_sec); 147 } 148 149 TEST(IOEventLoop, periodic) { 150 TestPeriodicEvents(1000000, 1, false); 151 } 152 153 TEST(IOEventLoop, periodic_precise) { 154 TestPeriodicEvents(1000, 100, true); 155 } 156 157 TEST(IOEventLoop, read_and_del_event) { 158 int fd[2]; 159 ASSERT_EQ(0, pipe(fd)); 160 IOEventLoop loop; 161 int count = 0; 162 IOEventRef ref = loop.AddReadEvent(fd[0], [&]() { 163 count++; 164 return IOEventLoop::DelEvent(ref); 165 }); 166 ASSERT_NE(nullptr, ref); 167 168 std::thread thread([&]() { 169 for (int i = 0; i < 100; ++i) { 170 usleep(1000); 171 char c; 172 write(fd[1], &c, 1); 173 } 174 }); 175 ASSERT_TRUE(loop.RunLoop()); 176 thread.join(); 177 ASSERT_EQ(1, count); 178 close(fd[0]); 179 close(fd[1]); 180 } 181 182 TEST(IOEventLoop, disable_enable_event) { 183 int fd[2]; 184 ASSERT_EQ(0, pipe(fd)); 185 IOEventLoop loop; 186 int count = 0; 187 IOEventRef ref = loop.AddWriteEvent(fd[1], [&]() { 188 count++; 189 return IOEventLoop::DisableEvent(ref); 190 }); 191 ASSERT_NE(nullptr, ref); 192 193 timeval tv; 194 tv.tv_sec = 0; 195 tv.tv_usec = 500000; 196 int periodic_count = 0; 197 ASSERT_TRUE(loop.AddPeriodicEvent(tv, [&]() { 198 periodic_count++; 199 if (periodic_count == 1) { 200 if (count != 1) { 201 return false; 202 } 203 return IOEventLoop::EnableEvent(ref); 204 } else { 205 if (count != 2) { 206 return false; 207 } 208 return loop.ExitLoop(); 209 } 210 })); 211 212 ASSERT_TRUE(loop.RunLoop()); 213 ASSERT_EQ(2, count); 214 ASSERT_EQ(2, periodic_count); 215 close(fd[0]); 216 close(fd[1]); 217 } 218