Home | History | Annotate | Download | only in qemu
      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