| #include "iolooper.h" |
| #include "qemu-common.h" |
| |
| /* An implementation of iolooper.h based on Unix select() */ |
| #ifdef _WIN32 |
| # include <winsock2.h> |
| #else |
| # include <sys/types.h> |
| # include <sys/select.h> |
| #endif |
| |
| struct IoLooper { |
| fd_set reads[1]; |
| fd_set writes[1]; |
| fd_set reads_result[1]; |
| fd_set writes_result[1]; |
| int max_fd; |
| int max_fd_valid; |
| }; |
| |
| IoLooper* |
| iolooper_new(void) |
| { |
| IoLooper* iol = qemu_malloc(sizeof(*iol)); |
| iolooper_reset(iol); |
| return iol; |
| } |
| |
| void |
| iolooper_free( IoLooper* iol ) |
| { |
| qemu_free(iol); |
| } |
| |
| void |
| iolooper_reset( IoLooper* iol ) |
| { |
| FD_ZERO(iol->reads); |
| FD_ZERO(iol->writes); |
| iol->max_fd = -1; |
| iol->max_fd_valid = 1; |
| } |
| |
| static void |
| iolooper_add_fd( IoLooper* iol, int fd ) |
| { |
| if (iol->max_fd_valid && fd > iol->max_fd) { |
| iol->max_fd = fd; |
| } |
| } |
| |
| static void |
| iolooper_del_fd( IoLooper* iol, int fd ) |
| { |
| if (iol->max_fd_valid && fd == iol->max_fd) |
| iol->max_fd_valid = 0; |
| } |
| |
| static int |
| iolooper_fd_count( IoLooper* iol ) |
| { |
| int max_fd = iol->max_fd; |
| int fd; |
| |
| if (iol->max_fd_valid) |
| return max_fd + 1; |
| |
| /* recompute max fd */ |
| for (fd = 0; fd < FD_SETSIZE; fd++) { |
| if (!FD_ISSET(fd, iol->reads) && !FD_ISSET(fd, iol->writes)) |
| continue; |
| |
| max_fd = fd; |
| } |
| iol->max_fd = max_fd; |
| iol->max_fd_valid = 1; |
| |
| return max_fd + 1; |
| } |
| |
| void |
| iolooper_add_read( IoLooper* iol, int fd ) |
| { |
| if (fd >= 0) { |
| iolooper_add_fd(iol, fd); |
| FD_SET(fd, iol->reads); |
| } |
| } |
| |
| void |
| iolooper_add_write( IoLooper* iol, int fd ) |
| { |
| if (fd >= 0) { |
| iolooper_add_fd(iol, fd); |
| FD_SET(fd, iol->writes); |
| } |
| } |
| |
| void |
| iolooper_del_read( IoLooper* iol, int fd ) |
| { |
| if (fd >= 0) { |
| iolooper_del_fd(iol, fd); |
| FD_CLR(fd, iol->reads); |
| } |
| } |
| |
| void |
| iolooper_del_write( IoLooper* iol, int fd ) |
| { |
| if (fd >= 0) { |
| iolooper_del_fd(iol, fd); |
| FD_CLR(fd, iol->reads); |
| } |
| } |
| |
| int |
| iolooper_poll( IoLooper* iol ) |
| { |
| int count = iolooper_fd_count(iol); |
| int ret; |
| fd_set errs; |
| |
| if (count == 0) |
| return 0; |
| |
| FD_ZERO(&errs); |
| |
| do { |
| struct timeval tv; |
| |
| tv.tv_sec = tv.tv_usec = 0; |
| |
| iol->reads_result[0] = iol->reads[0]; |
| iol->writes_result[0] = iol->writes[0]; |
| |
| ret = select( count, iol->reads_result, iol->writes_result, &errs, &tv); |
| } while (ret < 0 && errno == EINTR); |
| |
| return ret; |
| } |
| |
| int |
| iolooper_wait( IoLooper* iol, int64_t duration ) |
| { |
| int count = iolooper_fd_count(iol); |
| int ret; |
| fd_set errs; |
| |
| if (count == 0) |
| return 0; |
| |
| FD_ZERO(&errs); |
| |
| do { |
| iol->reads_result[0] = iol->reads[0]; |
| iol->writes_result[0] = iol->writes[0]; |
| |
| ret = select( count, iol->reads_result, iol->writes_result, &errs, NULL); |
| } while (ret < 0 && errno == EINTR); |
| |
| return ret; |
| } |
| |
| |
| int |
| iolooper_is_read( IoLooper* iol, int fd ) |
| { |
| return FD_ISSET(fd, iol->reads_result); |
| } |
| |
| int |
| iolooper_is_write( IoLooper* iol, int fd ) |
| { |
| return FD_ISSET(fd, iol->writes_result); |
| } |