1 #include "android/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 "android/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 CLAMP_MAC_TIMEOUT(duration); 179 180 if (duration < 0) 181 tm = NULL; 182 else { 183 tm = &tm0; 184 tm->tv_sec = duration / 1000; 185 tm->tv_usec = (duration - 1000*tm->tv_sec) * 1000; 186 } 187 188 FD_ZERO(&errs); 189 190 do { 191 iol->reads_result[0] = iol->reads[0]; 192 iol->writes_result[0] = iol->writes[0]; 193 194 ret = select( count, iol->reads_result, iol->writes_result, &errs, tm); 195 if (ret == 0) { 196 // Indicates timeout 197 errno = ETIMEDOUT; 198 } 199 } while (ret < 0 && errno == EINTR); 200 201 return ret; 202 } 203 204 205 int 206 iolooper_is_read( IoLooper* iol, int fd ) 207 { 208 return FD_ISSET(fd, iol->reads_result); 209 } 210 211 int 212 iolooper_is_write( IoLooper* iol, int fd ) 213 { 214 return FD_ISSET(fd, iol->writes_result); 215 } 216 217 int 218 iolooper_has_operations( IoLooper* iol ) 219 { 220 return iolooper_fd_count(iol) > 0; 221 } 222 223 int64_t 224 iolooper_now(void) 225 { 226 struct timeval time_now; 227 return gettimeofday(&time_now, NULL) ? -1 : (int64_t)time_now.tv_sec * 1000LL + 228 time_now.tv_usec / 1000; 229 } 230 231 int 232 iolooper_wait_absolute(IoLooper* iol, int64_t deadline) 233 { 234 int64_t timeout = deadline - iolooper_now(); 235 236 /* If the deadline has passed, set the timeout to 0, this allows us 237 * to poll the file descriptor nonetheless */ 238 if (timeout < 0) 239 timeout = 0; 240 241 return iolooper_wait(iol, timeout); 242 } 243