aboutsummaryrefslogtreecommitdiffstats
path: root/iolooper-select.c
diff options
context:
space:
mode:
Diffstat (limited to 'iolooper-select.c')
-rw-r--r--iolooper-select.c176
1 files changed, 176 insertions, 0 deletions
diff --git a/iolooper-select.c b/iolooper-select.c
new file mode 100644
index 0000000..74a5a3a
--- /dev/null
+++ b/iolooper-select.c
@@ -0,0 +1,176 @@
+#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);
+}