blob: 91dfece847491d1877008641dcce1fab2000cbb9 [file] [log] [blame]
David 'Digit' Turnerd413fa52013-12-14 23:35:20 +01001#include "android/iolooper.h"
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002#include "qemu-common.h"
3
4/* An implementation of iolooper.h based on Unix select() */
5#ifdef _WIN32
6# include <winsock2.h>
7#else
8# include <sys/types.h>
9# include <sys/select.h>
10#endif
David 'Digit' Turnercc330d42013-12-14 23:26:42 +010011#include "android/sockets.h"
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070012
13struct IoLooper {
14 fd_set reads[1];
15 fd_set writes[1];
16 fd_set reads_result[1];
17 fd_set writes_result[1];
18 int max_fd;
19 int max_fd_valid;
20};
21
22IoLooper*
23iolooper_new(void)
24{
Vladimir Chtchetkine9a33e852010-11-08 16:52:04 -080025 IoLooper* iol = malloc(sizeof(*iol));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070026 iolooper_reset(iol);
27 return iol;
28}
29
30void
31iolooper_free( IoLooper* iol )
32{
Vladimir Chtchetkine9a33e852010-11-08 16:52:04 -080033 free(iol);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070034}
35
36void
37iolooper_reset( IoLooper* iol )
38{
39 FD_ZERO(iol->reads);
40 FD_ZERO(iol->writes);
41 iol->max_fd = -1;
42 iol->max_fd_valid = 1;
43}
44
45static void
46iolooper_add_fd( IoLooper* iol, int fd )
47{
48 if (iol->max_fd_valid && fd > iol->max_fd) {
49 iol->max_fd = fd;
50 }
51}
52
53static void
54iolooper_del_fd( IoLooper* iol, int fd )
55{
56 if (iol->max_fd_valid && fd == iol->max_fd)
57 iol->max_fd_valid = 0;
58}
59
David 'Digit' Turner7a17b602010-11-17 17:58:29 +010060void
61iolooper_modify( IoLooper* iol, int fd, int oldflags, int newflags )
62{
63 if (fd < 0)
64 return;
65
66 int changed = oldflags ^ newflags;
67
68 if ((changed & IOLOOPER_READ) != 0) {
69 if ((newflags & IOLOOPER_READ) != 0)
David 'Digit' Turner1bb627c2010-11-18 16:10:45 +010070 iolooper_add_read(iol, fd);
David 'Digit' Turner7a17b602010-11-17 17:58:29 +010071 else
David 'Digit' Turner1bb627c2010-11-18 16:10:45 +010072 iolooper_del_read(iol, fd);
David 'Digit' Turner7a17b602010-11-17 17:58:29 +010073 }
74 if ((changed & IOLOOPER_WRITE) != 0) {
75 if ((newflags & IOLOOPER_WRITE) != 0)
David 'Digit' Turner1bb627c2010-11-18 16:10:45 +010076 iolooper_add_write(iol, fd);
David 'Digit' Turner7a17b602010-11-17 17:58:29 +010077 else
David 'Digit' Turner1bb627c2010-11-18 16:10:45 +010078 iolooper_del_write(iol, fd);
David 'Digit' Turner7a17b602010-11-17 17:58:29 +010079 }
80}
81
82
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070083static int
84iolooper_fd_count( IoLooper* iol )
85{
86 int max_fd = iol->max_fd;
87 int fd;
88
89 if (iol->max_fd_valid)
90 return max_fd + 1;
91
92 /* recompute max fd */
93 for (fd = 0; fd < FD_SETSIZE; fd++) {
94 if (!FD_ISSET(fd, iol->reads) && !FD_ISSET(fd, iol->writes))
95 continue;
96
97 max_fd = fd;
98 }
99 iol->max_fd = max_fd;
100 iol->max_fd_valid = 1;
101
102 return max_fd + 1;
103}
104
105void
106iolooper_add_read( IoLooper* iol, int fd )
107{
108 if (fd >= 0) {
109 iolooper_add_fd(iol, fd);
110 FD_SET(fd, iol->reads);
111 }
112}
113
114void
115iolooper_add_write( IoLooper* iol, int fd )
116{
117 if (fd >= 0) {
118 iolooper_add_fd(iol, fd);
119 FD_SET(fd, iol->writes);
120 }
121}
122
123void
124iolooper_del_read( IoLooper* iol, int fd )
125{
126 if (fd >= 0) {
127 iolooper_del_fd(iol, fd);
128 FD_CLR(fd, iol->reads);
129 }
130}
131
132void
133iolooper_del_write( IoLooper* iol, int fd )
134{
135 if (fd >= 0) {
136 iolooper_del_fd(iol, fd);
Vladimir Chtchetkine9a33e852010-11-08 16:52:04 -0800137 FD_CLR(fd, iol->writes);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700138 }
139}
140
141int
142iolooper_poll( IoLooper* iol )
143{
144 int count = iolooper_fd_count(iol);
145 int ret;
146 fd_set errs;
147
148 if (count == 0)
149 return 0;
150
151 FD_ZERO(&errs);
152
153 do {
154 struct timeval tv;
155
156 tv.tv_sec = tv.tv_usec = 0;
157
158 iol->reads_result[0] = iol->reads[0];
159 iol->writes_result[0] = iol->writes[0];
160
161 ret = select( count, iol->reads_result, iol->writes_result, &errs, &tv);
162 } while (ret < 0 && errno == EINTR);
163
164 return ret;
165}
166
167int
168iolooper_wait( IoLooper* iol, int64_t duration )
169{
170 int count = iolooper_fd_count(iol);
171 int ret;
172 fd_set errs;
David 'Digit' Turner9b98dbd2010-07-30 15:35:00 -0700173 struct timeval tm0, *tm = NULL;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700174
175 if (count == 0)
176 return 0;
177
Vladimir Chtchetkine10bc04f2012-03-16 09:21:02 -0700178 CLAMP_MAC_TIMEOUT(duration);
179
David 'Digit' Turner9b98dbd2010-07-30 15:35:00 -0700180 if (duration < 0)
181 tm = NULL;
182 else {
183 tm = &tm0;
184 tm->tv_sec = duration / 1000;
185 tm->tv_usec = (duration - 1000*tm->tv_sec) * 1000;
186 }
187
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700188 FD_ZERO(&errs);
189
190 do {
191 iol->reads_result[0] = iol->reads[0];
192 iol->writes_result[0] = iol->writes[0];
193
David 'Digit' Turner9b98dbd2010-07-30 15:35:00 -0700194 ret = select( count, iol->reads_result, iol->writes_result, &errs, tm);
Vladimir Chtchetkined8ba2ae2010-11-15 11:02:49 -0800195 if (ret == 0) {
196 // Indicates timeout
197 errno = ETIMEDOUT;
198 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700199 } while (ret < 0 && errno == EINTR);
200
201 return ret;
202}
203
204
205int
206iolooper_is_read( IoLooper* iol, int fd )
207{
208 return FD_ISSET(fd, iol->reads_result);
209}
210
211int
212iolooper_is_write( IoLooper* iol, int fd )
213{
214 return FD_ISSET(fd, iol->writes_result);
215}
Ot ten Thijecc19d3e2010-07-19 13:10:18 +0100216
217int
218iolooper_has_operations( IoLooper* iol )
219{
220 return iolooper_fd_count(iol) > 0;
221}
Vladimir Chtchetkined8ba2ae2010-11-15 11:02:49 -0800222
223int64_t
224iolooper_now(void)
225{
226 struct timeval time_now;
227 return gettimeofday(&time_now, NULL) ? -1 : (int64_t)time_now.tv_sec * 1000LL +
228 time_now.tv_usec / 1000;
229}
230
231int
232iolooper_wait_absolute(IoLooper* iol, int64_t deadline)
233{
234 int64_t timeout = deadline - iolooper_now();
David 'Digit' Turner1bb627c2010-11-18 16:10:45 +0100235
236 /* If the deadline has passed, set the timeout to 0, this allows us
237 * to poll the file descriptor nonetheless */
238 if (timeout < 0)
239 timeout = 0;
240
241 return iolooper_wait(iol, timeout);
Vladimir Chtchetkined8ba2ae2010-11-15 11:02:49 -0800242}