blob: 955204d177c455608db731331447b160ca492cc2 [file] [log] [blame]
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001#include "iolooper.h"
2#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
Vladimir Chtchetkine896e9942010-11-16 08:49:01 -080011#include "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
David 'Digit' Turner9b98dbd2010-07-30 15:35:00 -0700178 if (duration < 0)
179 tm = NULL;
180 else {
181 tm = &tm0;
182 tm->tv_sec = duration / 1000;
183 tm->tv_usec = (duration - 1000*tm->tv_sec) * 1000;
184 }
185
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700186 FD_ZERO(&errs);
187
188 do {
189 iol->reads_result[0] = iol->reads[0];
190 iol->writes_result[0] = iol->writes[0];
191
David 'Digit' Turner9b98dbd2010-07-30 15:35:00 -0700192 ret = select( count, iol->reads_result, iol->writes_result, &errs, tm);
Vladimir Chtchetkined8ba2ae2010-11-15 11:02:49 -0800193 if (ret == 0) {
194 // Indicates timeout
195 errno = ETIMEDOUT;
196 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700197 } while (ret < 0 && errno == EINTR);
198
199 return ret;
200}
201
202
203int
204iolooper_is_read( IoLooper* iol, int fd )
205{
206 return FD_ISSET(fd, iol->reads_result);
207}
208
209int
210iolooper_is_write( IoLooper* iol, int fd )
211{
212 return FD_ISSET(fd, iol->writes_result);
213}
Ot ten Thijecc19d3e2010-07-19 13:10:18 +0100214
215int
216iolooper_has_operations( IoLooper* iol )
217{
218 return iolooper_fd_count(iol) > 0;
219}
Vladimir Chtchetkined8ba2ae2010-11-15 11:02:49 -0800220
221int64_t
222iolooper_now(void)
223{
224 struct timeval time_now;
225 return gettimeofday(&time_now, NULL) ? -1 : (int64_t)time_now.tv_sec * 1000LL +
226 time_now.tv_usec / 1000;
227}
228
229int
230iolooper_wait_absolute(IoLooper* iol, int64_t deadline)
231{
232 int64_t timeout = deadline - iolooper_now();
David 'Digit' Turner1bb627c2010-11-18 16:10:45 +0100233
234 /* If the deadline has passed, set the timeout to 0, this allows us
235 * to poll the file descriptor nonetheless */
236 if (timeout < 0)
237 timeout = 0;
238
239 return iolooper_wait(iol, timeout);
Vladimir Chtchetkined8ba2ae2010-11-15 11:02:49 -0800240}