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