• 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     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 
186     FD_ZERO(&errs);
187 
188     do {
189         iol->reads_result[0]  = iol->reads[0];
190         iol->writes_result[0] = iol->writes[0];
191 
192         ret = select( count, iol->reads_result, iol->writes_result, &errs, tm);
193         if (ret == 0) {
194             // Indicates timeout
195             errno = ETIMEDOUT;
196         }
197     } while (ret < 0 && errno == EINTR);
198 
199     return ret;
200 }
201 
202 
203 int
iolooper_is_read(IoLooper * iol,int fd)204 iolooper_is_read( IoLooper*  iol, int  fd )
205 {
206     return FD_ISSET(fd, iol->reads_result);
207 }
208 
209 int
iolooper_is_write(IoLooper * iol,int fd)210 iolooper_is_write( IoLooper*  iol, int  fd )
211 {
212     return FD_ISSET(fd, iol->writes_result);
213 }
214 
215 int
iolooper_has_operations(IoLooper * iol)216 iolooper_has_operations( IoLooper* iol )
217 {
218     return iolooper_fd_count(iol) > 0;
219 }
220 
221 int64_t
iolooper_now(void)222 iolooper_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 
229 int
iolooper_wait_absolute(IoLooper * iol,int64_t deadline)230 iolooper_wait_absolute(IoLooper* iol, int64_t deadline)
231 {
232     int64_t timeout = deadline - iolooper_now();
233 
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);
240 }
241