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
12 struct IoLooper {
13 fd_set reads[1];
14 fd_set writes[1];
15 fd_set reads_result[1];
16 fd_set writes_result[1];
17 int max_fd;
18 int max_fd_valid;
19 };
20
21 IoLooper*
iolooper_new(void)22 iolooper_new(void)
23 {
24 IoLooper* iol = qemu_malloc(sizeof(*iol));
25 iolooper_reset(iol);
26 return iol;
27 }
28
29 void
iolooper_free(IoLooper * iol)30 iolooper_free( IoLooper* iol )
31 {
32 qemu_free(iol);
33 }
34
35 void
iolooper_reset(IoLooper * iol)36 iolooper_reset( IoLooper* iol )
37 {
38 FD_ZERO(iol->reads);
39 FD_ZERO(iol->writes);
40 iol->max_fd = -1;
41 iol->max_fd_valid = 1;
42 }
43
44 static void
iolooper_add_fd(IoLooper * iol,int fd)45 iolooper_add_fd( IoLooper* iol, int fd )
46 {
47 if (iol->max_fd_valid && fd > iol->max_fd) {
48 iol->max_fd = fd;
49 }
50 }
51
52 static void
iolooper_del_fd(IoLooper * iol,int fd)53 iolooper_del_fd( IoLooper* iol, int fd )
54 {
55 if (iol->max_fd_valid && fd == iol->max_fd)
56 iol->max_fd_valid = 0;
57 }
58
59 static int
iolooper_fd_count(IoLooper * iol)60 iolooper_fd_count( IoLooper* iol )
61 {
62 int max_fd = iol->max_fd;
63 int fd;
64
65 if (iol->max_fd_valid)
66 return max_fd + 1;
67
68 /* recompute max fd */
69 for (fd = 0; fd < FD_SETSIZE; fd++) {
70 if (!FD_ISSET(fd, iol->reads) && !FD_ISSET(fd, iol->writes))
71 continue;
72
73 max_fd = fd;
74 }
75 iol->max_fd = max_fd;
76 iol->max_fd_valid = 1;
77
78 return max_fd + 1;
79 }
80
81 void
iolooper_add_read(IoLooper * iol,int fd)82 iolooper_add_read( IoLooper* iol, int fd )
83 {
84 if (fd >= 0) {
85 iolooper_add_fd(iol, fd);
86 FD_SET(fd, iol->reads);
87 }
88 }
89
90 void
iolooper_add_write(IoLooper * iol,int fd)91 iolooper_add_write( IoLooper* iol, int fd )
92 {
93 if (fd >= 0) {
94 iolooper_add_fd(iol, fd);
95 FD_SET(fd, iol->writes);
96 }
97 }
98
99 void
iolooper_del_read(IoLooper * iol,int fd)100 iolooper_del_read( IoLooper* iol, int fd )
101 {
102 if (fd >= 0) {
103 iolooper_del_fd(iol, fd);
104 FD_CLR(fd, iol->reads);
105 }
106 }
107
108 void
iolooper_del_write(IoLooper * iol,int fd)109 iolooper_del_write( IoLooper* iol, int fd )
110 {
111 if (fd >= 0) {
112 iolooper_del_fd(iol, fd);
113 FD_CLR(fd, iol->reads);
114 }
115 }
116
117 int
iolooper_poll(IoLooper * iol)118 iolooper_poll( IoLooper* iol )
119 {
120 int count = iolooper_fd_count(iol);
121 int ret;
122 fd_set errs;
123
124 if (count == 0)
125 return 0;
126
127 FD_ZERO(&errs);
128
129 do {
130 struct timeval tv;
131
132 tv.tv_sec = tv.tv_usec = 0;
133
134 iol->reads_result[0] = iol->reads[0];
135 iol->writes_result[0] = iol->writes[0];
136
137 ret = select( count, iol->reads_result, iol->writes_result, &errs, &tv);
138 } while (ret < 0 && errno == EINTR);
139
140 return ret;
141 }
142
143 int
iolooper_wait(IoLooper * iol,int64_t duration)144 iolooper_wait( IoLooper* iol, int64_t duration )
145 {
146 int count = iolooper_fd_count(iol);
147 int ret;
148 fd_set errs;
149
150 if (count == 0)
151 return 0;
152
153 FD_ZERO(&errs);
154
155 do {
156 iol->reads_result[0] = iol->reads[0];
157 iol->writes_result[0] = iol->writes[0];
158
159 ret = select( count, iol->reads_result, iol->writes_result, &errs, NULL);
160 } while (ret < 0 && errno == EINTR);
161
162 return ret;
163 }
164
165
166 int
iolooper_is_read(IoLooper * iol,int fd)167 iolooper_is_read( IoLooper* iol, int fd )
168 {
169 return FD_ISSET(fd, iol->reads_result);
170 }
171
172 int
iolooper_is_write(IoLooper * iol,int fd)173 iolooper_is_write( IoLooper* iol, int fd )
174 {
175 return FD_ISSET(fd, iol->writes_result);
176 }
177