#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);
}