qemu/io/channel-watch.c
<<
>>
Prefs
   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
  24typedef struct QIOChannelFDSource QIOChannelFDSource;
  25struct QIOChannelFDSource {
  26    GSource parent;
  27    GPollFD fd;
  28    QIOChannel *ioc;
  29    GIOCondition condition;
  30};
  31
  32
  33#ifdef CONFIG_WIN32
  34typedef struct QIOChannelSocketSource QIOChannelSocketSource;
  35struct 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
  47typedef struct QIOChannelFDPairSource QIOChannelFDPairSource;
  48struct QIOChannelFDPairSource {
  49    GSource parent;
  50    GPollFD fdread;
  51    GPollFD fdwrite;
  52    QIOChannel *ioc;
  53    GIOCondition condition;
  54};
  55
  56
  57static gboolean
  58qio_channel_fd_source_prepare(GSource *source G_GNUC_UNUSED,
  59                              gint *timeout)
  60{
  61    *timeout = -1;
  62
  63    return FALSE;
  64}
  65
  66
  67static gboolean
  68qio_channel_fd_source_check(GSource *source)
  69{
  70    QIOChannelFDSource *ssource = (QIOChannelFDSource *)source;
  71
  72    return ssource->fd.revents & ssource->condition;
  73}
  74
  75
  76static gboolean
  77qio_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
  90static void
  91qio_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
 100static gboolean
 101qio_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 */
 114static gboolean
 115qio_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
 156static gboolean
 157qio_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
 168static void
 169qio_channel_socket_source_finalize(GSource *source)
 170{
 171    QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source;
 172
 173    object_unref(OBJECT(ssource->ioc));
 174}
 175
 176
 177GSourceFuncs 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
 186static gboolean
 187qio_channel_fd_pair_source_prepare(GSource *source G_GNUC_UNUSED,
 188                                   gint *timeout)
 189{
 190    *timeout = -1;
 191
 192    return FALSE;
 193}
 194
 195
 196static gboolean
 197qio_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
 207static gboolean
 208qio_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
 223static void
 224qio_channel_fd_pair_source_finalize(GSource *source)
 225{
 226    QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
 227
 228    object_unref(OBJECT(ssource->ioc));
 229}
 230
 231
 232GSourceFuncs 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
 240GSourceFuncs 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
 248GSource *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
 277GSource *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
 307GSource *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
 315GSource *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}
 348