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 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
 119    QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source;
 120    WSANETWORKEVENTS ev;
 121    fd_set rfds, wfds, xfds;
 122
 123    if (!ssource->condition) {
 124        return 0;
 125    }
 126
 127    WSAEnumNetworkEvents(ssource->socket, ssource->ioc->event, &ev);
 128
 129    FD_ZERO(&rfds);
 130    FD_ZERO(&wfds);
 131    FD_ZERO(&xfds);
 132    if (ssource->condition & G_IO_IN) {
 133        FD_SET((SOCKET)ssource->socket, &rfds);
 134    }
 135    if (ssource->condition & G_IO_OUT) {
 136        FD_SET((SOCKET)ssource->socket, &wfds);
 137    }
 138    if (ssource->condition & G_IO_PRI) {
 139        FD_SET((SOCKET)ssource->socket, &xfds);
 140    }
 141    ssource->revents = 0;
 142    if (select(0, &rfds, &wfds, &xfds, &tv0) == 0) {
 143        return 0;
 144    }
 145
 146    if (FD_ISSET(ssource->socket, &rfds)) {
 147        ssource->revents |= G_IO_IN;
 148    }
 149    if (FD_ISSET(ssource->socket, &wfds)) {
 150        ssource->revents |= G_IO_OUT;
 151    }
 152    if (FD_ISSET(ssource->socket, &xfds)) {
 153        ssource->revents |= G_IO_PRI;
 154    }
 155
 156    return ssource->revents;
 157}
 158
 159
 160static gboolean
 161qio_channel_socket_source_dispatch(GSource *source,
 162                                   GSourceFunc callback,
 163                                   gpointer user_data)
 164{
 165    QIOChannelFunc func = (QIOChannelFunc)callback;
 166    QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source;
 167
 168    return (*func)(ssource->ioc, ssource->revents, user_data);
 169}
 170
 171
 172static void
 173qio_channel_socket_source_finalize(GSource *source)
 174{
 175    QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source;
 176
 177    object_unref(OBJECT(ssource->ioc));
 178}
 179
 180
 181GSourceFuncs qio_channel_socket_source_funcs = {
 182    qio_channel_socket_source_prepare,
 183    qio_channel_socket_source_check,
 184    qio_channel_socket_source_dispatch,
 185    qio_channel_socket_source_finalize
 186};
 187#endif
 188
 189
 190static gboolean
 191qio_channel_fd_pair_source_prepare(GSource *source G_GNUC_UNUSED,
 192                                   gint *timeout)
 193{
 194    *timeout = -1;
 195
 196    return FALSE;
 197}
 198
 199
 200static gboolean
 201qio_channel_fd_pair_source_check(GSource *source)
 202{
 203    QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
 204    GIOCondition poll_condition = ssource->fdread.revents |
 205        ssource->fdwrite.revents;
 206
 207    return poll_condition & ssource->condition;
 208}
 209
 210
 211static gboolean
 212qio_channel_fd_pair_source_dispatch(GSource *source,
 213                                    GSourceFunc callback,
 214                                    gpointer user_data)
 215{
 216    QIOChannelFunc func = (QIOChannelFunc)callback;
 217    QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
 218    GIOCondition poll_condition = ssource->fdread.revents |
 219        ssource->fdwrite.revents;
 220
 221    return (*func)(ssource->ioc,
 222                   poll_condition & ssource->condition,
 223                   user_data);
 224}
 225
 226
 227static void
 228qio_channel_fd_pair_source_finalize(GSource *source)
 229{
 230    QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
 231
 232    object_unref(OBJECT(ssource->ioc));
 233}
 234
 235
 236GSourceFuncs qio_channel_fd_source_funcs = {
 237    qio_channel_fd_source_prepare,
 238    qio_channel_fd_source_check,
 239    qio_channel_fd_source_dispatch,
 240    qio_channel_fd_source_finalize
 241};
 242
 243
 244GSourceFuncs qio_channel_fd_pair_source_funcs = {
 245    qio_channel_fd_pair_source_prepare,
 246    qio_channel_fd_pair_source_check,
 247    qio_channel_fd_pair_source_dispatch,
 248    qio_channel_fd_pair_source_finalize
 249};
 250
 251
 252GSource *qio_channel_create_fd_watch(QIOChannel *ioc,
 253                                     int fd,
 254                                     GIOCondition condition)
 255{
 256    GSource *source;
 257    QIOChannelFDSource *ssource;
 258
 259    source = g_source_new(&qio_channel_fd_source_funcs,
 260                          sizeof(QIOChannelFDSource));
 261    ssource = (QIOChannelFDSource *)source;
 262
 263    ssource->ioc = ioc;
 264    object_ref(OBJECT(ioc));
 265
 266    ssource->condition = condition;
 267
 268#ifdef CONFIG_WIN32
 269    ssource->fd.fd = (gint64)_get_osfhandle(fd);
 270#else
 271    ssource->fd.fd = fd;
 272#endif
 273    ssource->fd.events = condition;
 274
 275    g_source_add_poll(source, &ssource->fd);
 276
 277    return source;
 278}
 279
 280#ifdef CONFIG_WIN32
 281GSource *qio_channel_create_socket_watch(QIOChannel *ioc,
 282                                         int socket,
 283                                         GIOCondition condition)
 284{
 285    GSource *source;
 286    QIOChannelSocketSource *ssource;
 287
 288#ifdef WIN32
 289    WSAEventSelect(socket, ioc->event,
 290                   FD_READ | FD_ACCEPT | FD_CLOSE |
 291                   FD_CONNECT | FD_WRITE | FD_OOB);
 292#endif
 293
 294    source = g_source_new(&qio_channel_socket_source_funcs,
 295                          sizeof(QIOChannelSocketSource));
 296    ssource = (QIOChannelSocketSource *)source;
 297
 298    ssource->ioc = ioc;
 299    object_ref(OBJECT(ioc));
 300
 301    ssource->condition = condition;
 302    ssource->socket = socket;
 303    ssource->revents = 0;
 304
 305    ssource->fd.fd = (gintptr)ioc->event;
 306    ssource->fd.events = G_IO_IN;
 307
 308    g_source_add_poll(source, &ssource->fd);
 309
 310    return source;
 311}
 312#else
 313GSource *qio_channel_create_socket_watch(QIOChannel *ioc,
 314                                         int socket,
 315                                         GIOCondition condition)
 316{
 317    return qio_channel_create_fd_watch(ioc, socket, condition);
 318}
 319#endif
 320
 321GSource *qio_channel_create_fd_pair_watch(QIOChannel *ioc,
 322                                          int fdread,
 323                                          int fdwrite,
 324                                          GIOCondition condition)
 325{
 326    GSource *source;
 327    QIOChannelFDPairSource *ssource;
 328
 329    source = g_source_new(&qio_channel_fd_pair_source_funcs,
 330                          sizeof(QIOChannelFDPairSource));
 331    ssource = (QIOChannelFDPairSource *)source;
 332
 333    ssource->ioc = ioc;
 334    object_ref(OBJECT(ioc));
 335
 336    ssource->condition = condition;
 337
 338#ifdef CONFIG_WIN32
 339    ssource->fdread.fd = (gint64)_get_osfhandle(fdread);
 340    ssource->fdwrite.fd = (gint64)_get_osfhandle(fdwrite);
 341#else
 342    ssource->fdread.fd = fdread;
 343    ssource->fdwrite.fd = fdwrite;
 344#endif
 345
 346    ssource->fdread.events = condition & G_IO_IN;
 347    ssource->fdwrite.events = condition & G_IO_OUT;
 348
 349    g_source_add_poll(source, &ssource->fdread);
 350    g_source_add_poll(source, &ssource->fdwrite);
 351
 352    return source;
 353}
 354