qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

channel-watch.c (8782B)


      1 /*
      2  * QEMU I/O channels watch helper APIs
      3  *
      4  * Copyright (c) 2015 Red Hat, Inc.
      5  *
      6  * This library is free software; you can redistribute it and/or
      7  * modify it under the terms of the GNU Lesser General Public
      8  * License as published by the Free Software Foundation; either
      9  * version 2.1 of the License, or (at your option) any later version.
     10  *
     11  * This library is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  * Lesser General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU Lesser General Public
     17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     18  *
     19  */
     20 
     21 #include "qemu/osdep.h"
     22 #include "io/channel-watch.h"
     23 
     24 typedef struct QIOChannelFDSource QIOChannelFDSource;
     25 struct QIOChannelFDSource {
     26     GSource parent;
     27     GPollFD fd;
     28     QIOChannel *ioc;
     29     GIOCondition condition;
     30 };
     31 
     32 
     33 #ifdef CONFIG_WIN32
     34 typedef struct QIOChannelSocketSource QIOChannelSocketSource;
     35 struct QIOChannelSocketSource {
     36     GSource parent;
     37     GPollFD fd;
     38     QIOChannel *ioc;
     39     SOCKET socket;
     40     int revents;
     41     GIOCondition condition;
     42 };
     43 
     44 #endif
     45 
     46 
     47 typedef struct QIOChannelFDPairSource QIOChannelFDPairSource;
     48 struct QIOChannelFDPairSource {
     49     GSource parent;
     50     GPollFD fdread;
     51     GPollFD fdwrite;
     52     QIOChannel *ioc;
     53     GIOCondition condition;
     54 };
     55 
     56 
     57 static gboolean
     58 qio_channel_fd_source_prepare(GSource *source G_GNUC_UNUSED,
     59                               gint *timeout)
     60 {
     61     *timeout = -1;
     62 
     63     return FALSE;
     64 }
     65 
     66 
     67 static gboolean
     68 qio_channel_fd_source_check(GSource *source)
     69 {
     70     QIOChannelFDSource *ssource = (QIOChannelFDSource *)source;
     71 
     72     return ssource->fd.revents & ssource->condition;
     73 }
     74 
     75 
     76 static gboolean
     77 qio_channel_fd_source_dispatch(GSource *source,
     78                                GSourceFunc callback,
     79                                gpointer user_data)
     80 {
     81     QIOChannelFunc func = (QIOChannelFunc)callback;
     82     QIOChannelFDSource *ssource = (QIOChannelFDSource *)source;
     83 
     84     return (*func)(ssource->ioc,
     85                    ssource->fd.revents & ssource->condition,
     86                    user_data);
     87 }
     88 
     89 
     90 static void
     91 qio_channel_fd_source_finalize(GSource *source)
     92 {
     93     QIOChannelFDSource *ssource = (QIOChannelFDSource *)source;
     94 
     95     object_unref(OBJECT(ssource->ioc));
     96 }
     97 
     98 
     99 #ifdef CONFIG_WIN32
    100 static gboolean
    101 qio_channel_socket_source_prepare(GSource *source G_GNUC_UNUSED,
    102                                   gint *timeout)
    103 {
    104     *timeout = -1;
    105 
    106     return FALSE;
    107 }
    108 
    109 
    110 /*
    111  * NB, this impl only works when the socket is in non-blocking
    112  * mode on Win32
    113  */
    114 static gboolean
    115 qio_channel_socket_source_check(GSource *source)
    116 {
    117     static struct timeval tv0;
    118     QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source;
    119     fd_set rfds, wfds, xfds;
    120 
    121     if (!ssource->condition) {
    122         return 0;
    123     }
    124 
    125     FD_ZERO(&rfds);
    126     FD_ZERO(&wfds);
    127     FD_ZERO(&xfds);
    128     if (ssource->condition & G_IO_IN) {
    129         FD_SET(ssource->socket, &rfds);
    130     }
    131     if (ssource->condition & G_IO_OUT) {
    132         FD_SET(ssource->socket, &wfds);
    133     }
    134     if (ssource->condition & G_IO_PRI) {
    135         FD_SET(ssource->socket, &xfds);
    136     }
    137     ssource->revents = 0;
    138     if (select(0, &rfds, &wfds, &xfds, &tv0) == 0) {
    139         return 0;
    140     }
    141 
    142     if (FD_ISSET(ssource->socket, &rfds)) {
    143         ssource->revents |= G_IO_IN;
    144     }
    145     if (FD_ISSET(ssource->socket, &wfds)) {
    146         ssource->revents |= G_IO_OUT;
    147     }
    148     if (FD_ISSET(ssource->socket, &xfds)) {
    149         ssource->revents |= G_IO_PRI;
    150     }
    151 
    152     return ssource->revents;
    153 }
    154 
    155 
    156 static gboolean
    157 qio_channel_socket_source_dispatch(GSource *source,
    158                                    GSourceFunc callback,
    159                                    gpointer user_data)
    160 {
    161     QIOChannelFunc func = (QIOChannelFunc)callback;
    162     QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source;
    163 
    164     return (*func)(ssource->ioc, ssource->revents, user_data);
    165 }
    166 
    167 
    168 static void
    169 qio_channel_socket_source_finalize(GSource *source)
    170 {
    171     QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source;
    172 
    173     object_unref(OBJECT(ssource->ioc));
    174 }
    175 
    176 
    177 GSourceFuncs qio_channel_socket_source_funcs = {
    178     qio_channel_socket_source_prepare,
    179     qio_channel_socket_source_check,
    180     qio_channel_socket_source_dispatch,
    181     qio_channel_socket_source_finalize
    182 };
    183 #endif
    184 
    185 
    186 static gboolean
    187 qio_channel_fd_pair_source_prepare(GSource *source G_GNUC_UNUSED,
    188                                    gint *timeout)
    189 {
    190     *timeout = -1;
    191 
    192     return FALSE;
    193 }
    194 
    195 
    196 static gboolean
    197 qio_channel_fd_pair_source_check(GSource *source)
    198 {
    199     QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
    200     GIOCondition poll_condition = ssource->fdread.revents |
    201         ssource->fdwrite.revents;
    202 
    203     return poll_condition & ssource->condition;
    204 }
    205 
    206 
    207 static gboolean
    208 qio_channel_fd_pair_source_dispatch(GSource *source,
    209                                     GSourceFunc callback,
    210                                     gpointer user_data)
    211 {
    212     QIOChannelFunc func = (QIOChannelFunc)callback;
    213     QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
    214     GIOCondition poll_condition = ssource->fdread.revents |
    215         ssource->fdwrite.revents;
    216 
    217     return (*func)(ssource->ioc,
    218                    poll_condition & ssource->condition,
    219                    user_data);
    220 }
    221 
    222 
    223 static void
    224 qio_channel_fd_pair_source_finalize(GSource *source)
    225 {
    226     QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
    227 
    228     object_unref(OBJECT(ssource->ioc));
    229 }
    230 
    231 
    232 GSourceFuncs qio_channel_fd_source_funcs = {
    233     qio_channel_fd_source_prepare,
    234     qio_channel_fd_source_check,
    235     qio_channel_fd_source_dispatch,
    236     qio_channel_fd_source_finalize
    237 };
    238 
    239 
    240 GSourceFuncs qio_channel_fd_pair_source_funcs = {
    241     qio_channel_fd_pair_source_prepare,
    242     qio_channel_fd_pair_source_check,
    243     qio_channel_fd_pair_source_dispatch,
    244     qio_channel_fd_pair_source_finalize
    245 };
    246 
    247 
    248 GSource *qio_channel_create_fd_watch(QIOChannel *ioc,
    249                                      int fd,
    250                                      GIOCondition condition)
    251 {
    252     GSource *source;
    253     QIOChannelFDSource *ssource;
    254 
    255     source = g_source_new(&qio_channel_fd_source_funcs,
    256                           sizeof(QIOChannelFDSource));
    257     ssource = (QIOChannelFDSource *)source;
    258 
    259     ssource->ioc = ioc;
    260     object_ref(OBJECT(ioc));
    261 
    262     ssource->condition = condition;
    263 
    264 #ifdef CONFIG_WIN32
    265     ssource->fd.fd = (gint64)_get_osfhandle(fd);
    266 #else
    267     ssource->fd.fd = fd;
    268 #endif
    269     ssource->fd.events = condition;
    270 
    271     g_source_add_poll(source, &ssource->fd);
    272 
    273     return source;
    274 }
    275 
    276 #ifdef CONFIG_WIN32
    277 GSource *qio_channel_create_socket_watch(QIOChannel *ioc,
    278                                          int socket,
    279                                          GIOCondition condition)
    280 {
    281     GSource *source;
    282     QIOChannelSocketSource *ssource;
    283 
    284     WSAEventSelect(socket, ioc->event,
    285                    FD_READ | FD_ACCEPT | FD_CLOSE |
    286                    FD_CONNECT | FD_WRITE | FD_OOB);
    287 
    288     source = g_source_new(&qio_channel_socket_source_funcs,
    289                           sizeof(QIOChannelSocketSource));
    290     ssource = (QIOChannelSocketSource *)source;
    291 
    292     ssource->ioc = ioc;
    293     object_ref(OBJECT(ioc));
    294 
    295     ssource->condition = condition;
    296     ssource->socket = socket;
    297     ssource->revents = 0;
    298 
    299     ssource->fd.fd = (gintptr)ioc->event;
    300     ssource->fd.events = G_IO_IN;
    301 
    302     g_source_add_poll(source, &ssource->fd);
    303 
    304     return source;
    305 }
    306 #else
    307 GSource *qio_channel_create_socket_watch(QIOChannel *ioc,
    308                                          int socket,
    309                                          GIOCondition condition)
    310 {
    311     return qio_channel_create_fd_watch(ioc, socket, condition);
    312 }
    313 #endif
    314 
    315 GSource *qio_channel_create_fd_pair_watch(QIOChannel *ioc,
    316                                           int fdread,
    317                                           int fdwrite,
    318                                           GIOCondition condition)
    319 {
    320     GSource *source;
    321     QIOChannelFDPairSource *ssource;
    322 
    323     source = g_source_new(&qio_channel_fd_pair_source_funcs,
    324                           sizeof(QIOChannelFDPairSource));
    325     ssource = (QIOChannelFDPairSource *)source;
    326 
    327     ssource->ioc = ioc;
    328     object_ref(OBJECT(ioc));
    329 
    330     ssource->condition = condition;
    331 
    332 #ifdef CONFIG_WIN32
    333     ssource->fdread.fd = (gint64)_get_osfhandle(fdread);
    334     ssource->fdwrite.fd = (gint64)_get_osfhandle(fdwrite);
    335 #else
    336     ssource->fdread.fd = fdread;
    337     ssource->fdwrite.fd = fdwrite;
    338 #endif
    339 
    340     ssource->fdread.events = condition & G_IO_IN;
    341     ssource->fdwrite.events = condition & G_IO_OUT;
    342 
    343     g_source_add_poll(source, &ssource->fdread);
    344     g_source_add_poll(source, &ssource->fdwrite);
    345 
    346     return source;
    347 }