• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #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
11 #include "sockets.h"
12 
13 struct 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 
22 IoLooper*
iolooper_new(void)23 iolooper_new(void)
24 {
25     IoLooper*  iol = malloc(sizeof(*iol));
26     iolooper_reset(iol);
27     return iol;
28 }
29 
30 void
iolooper_free(IoLooper * iol)31 iolooper_free( IoLooper*  iol )
32 {
33     free(iol);
34 }
35 
36 void
iolooper_reset(IoLooper * iol)37 iolooper_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 
45 static void
iolooper_add_fd(IoLooper * iol,int fd)46 iolooper_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 
53 static void
iolooper_del_fd(IoLooper * iol,int fd)54 iolooper_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 
60 void
iolooper_modify(IoLooper * iol,int fd,int oldflags,int newflags)61 iolooper_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)
70             iolooper_add_read(iol, fd);
71         else
72             iolooper_del_read(iol, fd);
73     }
74     if ((changed & IOLOOPER_WRITE) != 0) {
75         if ((newflags & IOLOOPER_WRITE) != 0)
76             iolooper_add_write(iol, fd);
77         else
78             iolooper_del_write(iol, fd);
79     }
80 }
81 
82 
83 static int
iolooper_fd_count(IoLooper * iol)84 iolooper_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 
105 void
iolooper_add_read(IoLooper * iol,int fd)106 iolooper_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 
114 void
iolooper_add_write(IoLooper * iol,int fd)115 iolooper_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 
123 void
iolooper_del_read(IoLooper * iol,int fd)124 iolooper_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 
132 void
iolooper_del_write(IoLooper * iol,int fd)133 iolooper_del_write( IoLooper*  iol, int  fd )
134 {
135     if (fd >= 0) {
136         iolooper_del_fd(iol, fd);
137         FD_CLR(fd, iol->writes);
138     }
139 }
140 
141 int
iolooper_poll(IoLooper * iol)142 iolooper_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 
167 int
iolooper_wait(IoLooper * iol,int64_t duration)168 iolooper_wait( IoLooper*  iol, int64_t  duration )
169 {
170     int     count = iolooper_fd_count(iol);
171     int     ret;
172     fd_set  errs;
173     struct timeval tm0, *tm = NULL;
174 
175     if (count == 0)
176         return 0;
177 
178     CLAMP_MAC_TIMEOUT(duration);
179 
180     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 
188     FD_ZERO(&errs);
189 
190     do {
191         iol->reads_result[0]  = iol->reads[0];
192         iol->writes_result[0] = iol->writes[0];
193 
194         ret = select( count, iol->reads_result, iol->writes_result, &errs, tm);
195         if (ret == 0) {
196             // Indicates timeout
197             errno = ETIMEDOUT;
198         }
199     } while (ret < 0 && errno == EINTR);
200 
201     return ret;
202 }
203 
204 
205 int
iolooper_is_read(IoLooper * iol,int fd)206 iolooper_is_read( IoLooper*  iol, int  fd )
207 {
208     return FD_ISSET(fd, iol->reads_result);
209 }
210 
211 int
iolooper_is_write(IoLooper * iol,int fd)212 iolooper_is_write( IoLooper*  iol, int  fd )
213 {
214     return FD_ISSET(fd, iol->writes_result);
215 }
216 
217 int
iolooper_has_operations(IoLooper * iol)218 iolooper_has_operations( IoLooper* iol )
219 {
220     return iolooper_fd_count(iol) > 0;
221 }
222 
223 int64_t
iolooper_now(void)224 iolooper_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 
231 int
iolooper_wait_absolute(IoLooper * iol,int64_t deadline)232 iolooper_wait_absolute(IoLooper* iol, int64_t deadline)
233 {
234     int64_t timeout = deadline - iolooper_now();
235 
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);
242 }
243