Home | History | Annotate | Download | only in event_injector
      1 /*
      2 * Copyright (C) 2011 The Android Open Source Project
      3 *
      4 * Licensed under the Apache License, Version 2.0 (the "License");
      5 * you may not use this file except in compliance with the License.
      6 * You may obtain a copy of the License at
      7 *
      8 * http://www.apache.org/licenses/LICENSE-2.0
      9 *
     10 * Unless required by applicable law or agreed to in writing, software
     11 * distributed under the License is distributed on an "AS IS" BASIS,
     12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 * See the License for the specific language governing permissions and
     14 * limitations under the License.
     15 */
     16 #include <errno.h>
     17 #include <stdlib.h>
     18 #include "iolooper.h"
     19 #include "sockets.h"
     20 
     21 /* An implementation of iolooper.h based on Unix select() */
     22 #ifdef _WIN32
     23 #  include <winsock2.h>
     24 #  include <time.h>
     25 #else
     26 #  include <sys/types.h>
     27 #  include <sys/select.h>
     28 #  include <sys/time.h>
     29 #endif
     30 
     31 struct IoLooper {
     32     fd_set   reads[1];
     33     fd_set   writes[1];
     34     fd_set   reads_result[1];
     35     fd_set   writes_result[1];
     36     int      max_fd;
     37     int      max_fd_valid;
     38 };
     39 
     40 IoLooper*
     41 iolooper_new(void)
     42 {
     43     IoLooper*  iol = malloc(sizeof(*iol));
     44     iolooper_reset(iol);
     45     return iol;
     46 }
     47 
     48 void
     49 iolooper_free( IoLooper*  iol )
     50 {
     51     free(iol);
     52 }
     53 
     54 void
     55 iolooper_reset( IoLooper*  iol )
     56 {
     57     FD_ZERO(iol->reads);
     58     FD_ZERO(iol->writes);
     59     iol->max_fd = -1;
     60     iol->max_fd_valid = 1;
     61 }
     62 
     63 static void
     64 iolooper_add_fd( IoLooper*  iol, int fd )
     65 {
     66     if (iol->max_fd_valid && fd > iol->max_fd) {
     67         iol->max_fd = fd;
     68     }
     69 }
     70 
     71 static void
     72 iolooper_del_fd( IoLooper*  iol, int fd )
     73 {
     74     if (iol->max_fd_valid && fd == iol->max_fd)
     75         iol->max_fd_valid = 0;
     76 }
     77 
     78 void
     79 iolooper_modify( IoLooper* iol, int fd, int oldflags, int newflags )
     80 {
     81     if (fd < 0)
     82         return;
     83 
     84     int changed = oldflags ^ newflags;
     85 
     86     if ((changed & IOLOOPER_READ) != 0) {
     87         if ((newflags & IOLOOPER_READ) != 0)
     88             iolooper_add_read(iol, fd);
     89         else
     90             iolooper_del_read(iol, fd);
     91     }
     92     if ((changed & IOLOOPER_WRITE) != 0) {
     93         if ((newflags & IOLOOPER_WRITE) != 0)
     94             iolooper_add_write(iol, fd);
     95         else
     96             iolooper_del_write(iol, fd);
     97     }
     98 }
     99 
    100 
    101 static int
    102 iolooper_fd_count( IoLooper*  iol )
    103 {
    104     int  max_fd = iol->max_fd;
    105     int  fd;
    106 
    107     if (iol->max_fd_valid)
    108         return max_fd + 1;
    109 
    110     /* recompute max fd */
    111     for (fd = 0; fd < FD_SETSIZE; fd++) {
    112         if (!FD_ISSET(fd, iol->reads) && !FD_ISSET(fd, iol->writes))
    113             continue;
    114 
    115         max_fd = fd;
    116     }
    117     iol->max_fd       = max_fd;
    118     iol->max_fd_valid = 1;
    119 
    120     return max_fd + 1;
    121 }
    122 
    123 void
    124 iolooper_add_read( IoLooper*  iol, int  fd )
    125 {
    126     if (fd >= 0) {
    127         iolooper_add_fd(iol, fd);
    128         FD_SET(fd, iol->reads);
    129     }
    130 }
    131 
    132 void
    133 iolooper_add_write( IoLooper*  iol, int  fd )
    134 {
    135     if (fd >= 0) {
    136         iolooper_add_fd(iol, fd);
    137         FD_SET(fd, iol->writes);
    138     }
    139 }
    140 
    141 void
    142 iolooper_del_read( IoLooper*  iol, int  fd )
    143 {
    144     if (fd >= 0) {
    145         iolooper_del_fd(iol, fd);
    146         FD_CLR(fd, iol->reads);
    147     }
    148 }
    149 
    150 void
    151 iolooper_del_write( IoLooper*  iol, int  fd )
    152 {
    153     if (fd >= 0) {
    154         iolooper_del_fd(iol, fd);
    155         FD_CLR(fd, iol->writes);
    156     }
    157 }
    158 
    159 int
    160 iolooper_poll( IoLooper*  iol )
    161 {
    162     int     count = iolooper_fd_count(iol);
    163     int     ret;
    164     fd_set  errs;
    165 
    166     if (count == 0)
    167         return 0;
    168 
    169     FD_ZERO(&errs);
    170 
    171     do {
    172         struct timeval  tv;
    173 
    174         tv.tv_sec = tv.tv_usec = 0;
    175 
    176         iol->reads_result[0]  = iol->reads[0];
    177         iol->writes_result[0] = iol->writes[0];
    178 
    179         ret = select( count, iol->reads_result, iol->writes_result, &errs, &tv);
    180     } while (ret < 0 && errno == EINTR);
    181 
    182     return ret;
    183 }
    184 
    185 int
    186 iolooper_wait( IoLooper*  iol, int64_t  duration )
    187 {
    188     int     count = iolooper_fd_count(iol);
    189     int     ret;
    190     fd_set  errs;
    191     struct timeval tm0, *tm = NULL;
    192 
    193     if (count == 0)
    194         return 0;
    195 
    196     if (duration < 0)
    197         tm = NULL;
    198     else {
    199         tm = &tm0;
    200         tm->tv_sec  = duration / 1000;
    201         tm->tv_usec = (duration - 1000*tm->tv_sec) * 1000;
    202     }
    203 
    204     FD_ZERO(&errs);
    205 
    206     do {
    207         iol->reads_result[0]  = iol->reads[0];
    208         iol->writes_result[0] = iol->writes[0];
    209 
    210         ret = select( count, iol->reads_result, iol->writes_result, &errs, tm);
    211         if (ret == 0) {
    212             // Indicates timeout
    213             errno = ETIMEDOUT;
    214         }
    215     } while (ret < 0 && errno == EINTR);
    216 
    217     return ret;
    218 }
    219 
    220 
    221 int
    222 iolooper_is_read( IoLooper*  iol, int  fd )
    223 {
    224     return FD_ISSET(fd, iol->reads_result);
    225 }
    226 
    227 int
    228 iolooper_is_write( IoLooper*  iol, int  fd )
    229 {
    230     return FD_ISSET(fd, iol->writes_result);
    231 }
    232 
    233 int
    234 iolooper_has_operations( IoLooper* iol )
    235 {
    236     return iolooper_fd_count(iol) > 0;
    237 }
    238 
    239 int64_t
    240 iolooper_now(void)
    241 {
    242 #ifdef _WIN32
    243     FILETIME now;
    244     int64_t now_100ns;
    245 
    246     GetSystemTimeAsFileTime(&now);
    247 
    248     /* Get the time as hundreds of nanosecond intervals since
    249        12:00 AM January 1t 1601 UTC. We don't really need
    250        to compute the value relative to the Posix epoch */
    251     now_100ns = ((int64_t)now.dwHighDateTime << 32) | now.dwLowDateTime;
    252 
    253     /* 100 ns == 0.1 us == 0.0001 ms */
    254     return now_100ns / 10000LL;
    255 
    256 #else /* !_WIN32 */
    257     struct timeval time_now;
    258     return gettimeofday(&time_now, NULL) ? -1 : (int64_t)time_now.tv_sec * 1000LL +
    259                                                 time_now.tv_usec / 1000;
    260 #endif /* !_WIN32 */
    261 }
    262 
    263 int
    264 iolooper_wait_absolute(IoLooper* iol, int64_t deadline)
    265 {
    266     int64_t timeout = deadline - iolooper_now();
    267 
    268     /* If the deadline has passed, set the timeout to 0, this allows us
    269      * to poll the file descriptor nonetheless */
    270     if (timeout < 0)
    271         timeout = 0;
    272 
    273     return iolooper_wait(iol, timeout);
    274 }
    275