blob: 658fe82091261adc7f3cd124c0a339dae05ab553 [file] [log] [blame]
Yabin Cui3e4c5952016-07-26 15:03:27 -07001/*
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
Yabin Cui5be914d2016-11-29 15:21:13 -080021#include <atomic>
Yabin Cui3e4c5952016-07-26 15:03:27 -070022#include <chrono>
23#include <thread>
24
Yabin Cuif6e5e0a2019-01-22 10:54:13 -080025#include <android-base/logging.h>
26
Yabin Cuifaa7b922021-01-11 17:35:57 -080027using namespace simpleperf;
28
Yabin Cuidbbda302016-07-28 12:55:41 -070029TEST(IOEventLoop, read) {
30 int fd[2];
31 ASSERT_EQ(0, pipe(fd));
32 IOEventLoop loop;
Yabin Cuia383c112016-10-19 11:04:56 -070033 int count = 0;
34 int retry_count = 0;
Yabin Cui825e56b2016-08-26 18:25:21 -070035 ASSERT_NE(nullptr, loop.AddReadEvent(fd[0], [&]() {
Yabin Cuidbbda302016-07-28 12:55:41 -070036 while (true) {
37 char c;
38 int ret = read(fd[0], &c, 1);
39 if (ret == 1) {
40 if (++count == 100) {
41 return loop.ExitLoop();
42 }
43 } else if (ret == -1 && errno == EAGAIN) {
44 retry_count++;
45 break;
46 } else {
47 return false;
48 }
49 }
50 return true;
51 }));
52 std::thread thread([&]() {
53 for (int i = 0; i < 100; ++i) {
54 usleep(1000);
55 char c;
Yabin Cuif6e5e0a2019-01-22 10:54:13 -080056 CHECK_EQ(write(fd[1], &c, 1), 1);
Yabin Cuidbbda302016-07-28 12:55:41 -070057 }
58 });
59 ASSERT_TRUE(loop.RunLoop());
60 thread.join();
61 ASSERT_EQ(100, count);
62 // Test retry_count to make sure we are not doing blocking read.
63 ASSERT_GT(retry_count, 0);
64 close(fd[0]);
65 close(fd[1]);
66}
67
Yabin Cuia383c112016-10-19 11:04:56 -070068TEST(IOEventLoop, write) {
69 int fd[2];
70 ASSERT_EQ(0, pipe(fd));
71 IOEventLoop loop;
72 int count = 0;
73 ASSERT_NE(nullptr, loop.AddWriteEvent(fd[1], [&]() {
74 int ret = 0;
75 char buf[4096];
76 while ((ret = write(fd[1], buf, sizeof(buf))) > 0) {
77 }
78 if (ret == -1 && errno == EAGAIN) {
79 if (++count == 100) {
80 loop.ExitLoop();
81 }
82 return true;
83 }
84 return false;
85 }));
86 std::thread thread([&]() {
87 usleep(500000);
88 while (true) {
89 usleep(1000);
90 char buf[4096];
91 if (read(fd[0], buf, sizeof(buf)) <= 0) {
92 break;
93 }
94 }
95 });
96 ASSERT_TRUE(loop.RunLoop());
97 // close fd[1] to make read thread stop.
98 close(fd[1]);
99 thread.join();
100 close(fd[0]);
101 ASSERT_EQ(100, count);
102}
103
Yabin Cui3e4c5952016-07-26 15:03:27 -0700104TEST(IOEventLoop, signal) {
105 IOEventLoop loop;
Yabin Cuia383c112016-10-19 11:04:56 -0700106 int count = 0;
Yabin Cui3e4c5952016-07-26 15:03:27 -0700107 ASSERT_TRUE(loop.AddSignalEvent(SIGINT, [&]() {
108 if (++count == 100) {
109 loop.ExitLoop();
110 }
111 return true;
112 }));
Yabin Cui5be914d2016-11-29 15:21:13 -0800113 std::atomic<bool> stop_thread(false);
114 std::thread thread([&]() {
115 while (!stop_thread) {
Yabin Cui3e4c5952016-07-26 15:03:27 -0700116 usleep(1000);
117 kill(getpid(), SIGINT);
118 }
119 });
120 ASSERT_TRUE(loop.RunLoop());
Yabin Cui5be914d2016-11-29 15:21:13 -0800121 stop_thread = true;
Yabin Cui3e4c5952016-07-26 15:03:27 -0700122 thread.join();
123 ASSERT_EQ(100, count);
124}
125
Yabin Cui76624282017-10-23 12:02:28 -0700126void TestPeriodicEvents(int period_in_us, int iterations, bool precise) {
Yabin Cui3e4c5952016-07-26 15:03:27 -0700127 timeval tv;
Yabin Cui76624282017-10-23 12:02:28 -0700128 tv.tv_sec = period_in_us / 1000000;
129 tv.tv_usec = period_in_us % 1000000;
Yabin Cuia383c112016-10-19 11:04:56 -0700130 int count = 0;
Yabin Cui3e4c5952016-07-26 15:03:27 -0700131 IOEventLoop loop;
Yabin Cui76624282017-10-23 12:02:28 -0700132 if (precise) {
133 ASSERT_TRUE(loop.UsePreciseTimer());
134 }
Yabin Cui3e4c5952016-07-26 15:03:27 -0700135 ASSERT_TRUE(loop.AddPeriodicEvent(tv, [&]() {
Yabin Cui76624282017-10-23 12:02:28 -0700136 if (++count == iterations) {
Yabin Cui3e4c5952016-07-26 15:03:27 -0700137 loop.ExitLoop();
138 }
139 return true;
140 }));
141 auto start_time = std::chrono::steady_clock::now();
142 ASSERT_TRUE(loop.RunLoop());
143 auto end_time = std::chrono::steady_clock::now();
Yabin Cui76624282017-10-23 12:02:28 -0700144 ASSERT_EQ(iterations, count);
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +0200145 double time_used =
146 std::chrono::duration_cast<std::chrono::duration<double>>(end_time - start_time).count();
Yabin Cui76624282017-10-23 12:02:28 -0700147 double min_time_in_sec = period_in_us / 1e6 * iterations;
Yabin Cui3c1f59f2021-02-02 10:15:40 -0800148 double max_time_in_sec = min_time_in_sec + (precise ? 0.3 : 1);
Yabin Cui76624282017-10-23 12:02:28 -0700149 ASSERT_GE(time_used, min_time_in_sec);
150 ASSERT_LT(time_used, max_time_in_sec);
151}
152
153TEST(IOEventLoop, periodic) {
154 TestPeriodicEvents(1000000, 1, false);
155}
156
157TEST(IOEventLoop, periodic_precise) {
158 TestPeriodicEvents(1000, 100, true);
Yabin Cui3e4c5952016-07-26 15:03:27 -0700159}
Yabin Cui825e56b2016-08-26 18:25:21 -0700160
161TEST(IOEventLoop, read_and_del_event) {
162 int fd[2];
163 ASSERT_EQ(0, pipe(fd));
164 IOEventLoop loop;
Yabin Cuia383c112016-10-19 11:04:56 -0700165 int count = 0;
Yabin Cui825e56b2016-08-26 18:25:21 -0700166 IOEventRef ref = loop.AddReadEvent(fd[0], [&]() {
167 count++;
168 return IOEventLoop::DelEvent(ref);
169 });
170 ASSERT_NE(nullptr, ref);
171
172 std::thread thread([&]() {
173 for (int i = 0; i < 100; ++i) {
174 usleep(1000);
175 char c;
Yabin Cuif6e5e0a2019-01-22 10:54:13 -0800176 CHECK_EQ(write(fd[1], &c, 1), 1);
Yabin Cui825e56b2016-08-26 18:25:21 -0700177 }
178 });
179 ASSERT_TRUE(loop.RunLoop());
180 thread.join();
181 ASSERT_EQ(1, count);
182 close(fd[0]);
183 close(fd[1]);
184}
Yabin Cuia383c112016-10-19 11:04:56 -0700185
186TEST(IOEventLoop, disable_enable_event) {
187 int fd[2];
188 ASSERT_EQ(0, pipe(fd));
189 IOEventLoop loop;
190 int count = 0;
191 IOEventRef ref = loop.AddWriteEvent(fd[1], [&]() {
192 count++;
193 return IOEventLoop::DisableEvent(ref);
194 });
195 ASSERT_NE(nullptr, ref);
196
197 timeval tv;
198 tv.tv_sec = 0;
199 tv.tv_usec = 500000;
200 int periodic_count = 0;
201 ASSERT_TRUE(loop.AddPeriodicEvent(tv, [&]() {
202 periodic_count++;
203 if (periodic_count == 1) {
204 if (count != 1) {
205 return false;
206 }
207 return IOEventLoop::EnableEvent(ref);
208 } else {
209 if (count != 2) {
210 return false;
211 }
212 return loop.ExitLoop();
213 }
214 }));
215
216 ASSERT_TRUE(loop.RunLoop());
217 ASSERT_EQ(2, count);
218 ASSERT_EQ(2, periodic_count);
219 close(fd[0]);
220 close(fd[1]);
221}
Yabin Cuiacf04b22018-04-18 13:10:40 -0700222
Yabin Cuic8571d42018-06-06 11:20:39 -0700223TEST(IOEventLoop, disable_enable_periodic_event) {
224 timeval tv;
225 tv.tv_sec = 0;
226 tv.tv_usec = 200000;
227 IOEventLoop loop;
228 IOEventRef wait_ref = loop.AddPeriodicEvent(tv, [&]() { return loop.ExitLoop(); });
229 ASSERT_TRUE(wait_ref != nullptr);
230 ASSERT_TRUE(loop.DisableEvent(wait_ref));
231
232 tv.tv_sec = 0;
233 tv.tv_usec = 100000;
234 size_t periodic_count = 0;
235 IOEventRef ref = loop.AddPeriodicEvent(tv, [&]() {
236 if (!loop.DisableEvent(ref)) {
237 return false;
238 }
239 periodic_count++;
240 if (periodic_count < 2u) {
241 return loop.EnableEvent(ref);
242 }
243 return loop.EnableEvent(wait_ref);
244 });
245 ASSERT_TRUE(loop.RunLoop());
246 ASSERT_EQ(2u, periodic_count);
247}
248
Yabin Cuiacf04b22018-04-18 13:10:40 -0700249TEST(IOEventLoop, exit_before_loop) {
250 IOEventLoop loop;
251 ASSERT_TRUE(loop.ExitLoop());
252}
Yabin Cuic3cc93b2022-03-31 16:46:16 -0700253
254TEST(IOEventLoop, priority) {
255 int low_priority_fd[2];
256 ASSERT_EQ(0, pipe(low_priority_fd));
257 int high_priority_fd[2];
258 ASSERT_EQ(0, pipe(high_priority_fd));
259
260 IOEventLoop loop;
261 int count = 0;
262
263 ASSERT_NE(nullptr, loop.AddReadEvent(
264 low_priority_fd[0],
265 [&]() {
266 char c;
267 read(low_priority_fd[0], &c, 1);
268 CHECK_EQ(count, 1);
269 count++;
270 return loop.ExitLoop();
271 },
272 IOEventLowPriority));
273
274 ASSERT_NE(nullptr, loop.AddReadEvent(
275 high_priority_fd[0],
276 [&]() {
277 char c;
278 read(high_priority_fd[0], &c, 1);
279 CHECK_EQ(count, 0);
280 count++;
281 return true;
282 },
283 IOEventHighPriority));
284
285 char c;
286 CHECK_EQ(write(low_priority_fd[1], &c, 1), 1);
287 CHECK_EQ(write(high_priority_fd[1], &c, 1), 1);
288 ASSERT_TRUE(loop.RunLoop());
289 ASSERT_EQ(2, count);
290 for (int i = 0; i < 2; i++) {
291 close(low_priority_fd[i]);
292 close(high_priority_fd[i]);
293 }
294}