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