• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TEST(IOEventLoop,read)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 
TEST(IOEventLoop,write)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 
TEST(IOEventLoop,signal)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 
TEST(IOEventLoop,periodic)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 
TEST(IOEventLoop,read_and_del_event)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 
TEST(IOEventLoop,disable_enable_event)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