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* 23 iolooper_new(void) 24 { 25 IoLooper* iol = malloc(sizeof(*iol)); 26 iolooper_reset(iol); 27 return iol; 28 } 29 30 void 31 iolooper_free( IoLooper* iol ) 32 { 33 free(iol); 34 } 35 36 void 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 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 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 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 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 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 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 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 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 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 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 204 iolooper_is_read( IoLooper* iol, int fd ) 205 { 206 return FD_ISSET(fd, iol->reads_result); 207 } 208 209 int 210 iolooper_is_write( IoLooper* iol, int fd ) 211 { 212 return FD_ISSET(fd, iol->writes_result); 213 } 214 215 int 216 iolooper_has_operations( IoLooper* iol ) 217 { 218 return iolooper_fd_count(iol) > 0; 219 } 220 221 int64_t 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 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