iolooper-select.c revision d8ba2ae8942abd9757338fc110ce6d215c486b1c
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
12struct 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
21IoLooper*
22iolooper_new(void)
23{
24    IoLooper*  iol = malloc(sizeof(*iol));
25    iolooper_reset(iol);
26    return iol;
27}
28
29void
30iolooper_free( IoLooper*  iol )
31{
32    free(iol);
33}
34
35void
36iolooper_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
44static void
45iolooper_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
52static void
53iolooper_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
59static int
60iolooper_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
81void
82iolooper_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
90void
91iolooper_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
99void
100iolooper_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
108void
109iolooper_del_write( IoLooper*  iol, int  fd )
110{
111    if (fd >= 0) {
112        iolooper_del_fd(iol, fd);
113        FD_CLR(fd, iol->writes);
114    }
115}
116
117int
118iolooper_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
143int
144iolooper_wait( IoLooper*  iol, int64_t  duration )
145{
146    int     count = iolooper_fd_count(iol);
147    int     ret;
148    fd_set  errs;
149    struct timeval tm0, *tm = NULL;
150
151    if (count == 0)
152        return 0;
153
154    if (duration < 0)
155        tm = NULL;
156    else {
157        tm = &tm0;
158        tm->tv_sec  = duration / 1000;
159        tm->tv_usec = (duration - 1000*tm->tv_sec) * 1000;
160    }
161
162    FD_ZERO(&errs);
163
164    do {
165        iol->reads_result[0]  = iol->reads[0];
166        iol->writes_result[0] = iol->writes[0];
167
168        ret = select( count, iol->reads_result, iol->writes_result, &errs, tm);
169        if (ret == 0) {
170            // Indicates timeout
171            errno = ETIMEDOUT;
172        }
173    } while (ret < 0 && errno == EINTR);
174
175    return ret;
176}
177
178
179int
180iolooper_is_read( IoLooper*  iol, int  fd )
181{
182    return FD_ISSET(fd, iol->reads_result);
183}
184
185int
186iolooper_is_write( IoLooper*  iol, int  fd )
187{
188    return FD_ISSET(fd, iol->writes_result);
189}
190
191int
192iolooper_has_operations( IoLooper* iol )
193{
194    return iolooper_fd_count(iol) > 0;
195}
196
197int64_t
198iolooper_now(void)
199{
200    struct timeval time_now;
201    return gettimeofday(&time_now, NULL) ? -1 : (int64_t)time_now.tv_sec * 1000LL +
202                                                time_now.tv_usec / 1000;
203}
204
205int
206iolooper_wait_absolute(IoLooper* iol, int64_t deadline)
207{
208    int64_t timeout = deadline - iolooper_now();
209    return (timeout >= 0) ? iolooper_wait(iol, timeout) : 0;
210}
211