qemu/io/channel.c
<<
>>
Prefs
   1/*
   2 * QEMU I/O channels
   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.h"
  23#include "qapi/error.h"
  24#include "qemu/coroutine.h"
  25
  26bool qio_channel_has_feature(QIOChannel *ioc,
  27                             QIOChannelFeature feature)
  28{
  29    return ioc->features & (1 << feature);
  30}
  31
  32
  33ssize_t qio_channel_readv_full(QIOChannel *ioc,
  34                               const struct iovec *iov,
  35                               size_t niov,
  36                               int **fds,
  37                               size_t *nfds,
  38                               Error **errp)
  39{
  40    QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
  41
  42    if ((fds || nfds) &&
  43        !(ioc->features & (1 << QIO_CHANNEL_FEATURE_FD_PASS))) {
  44        error_setg_errno(errp, EINVAL,
  45                         "Channel does not support file descriptor passing");
  46        return -1;
  47    }
  48
  49    return klass->io_readv(ioc, iov, niov, fds, nfds, errp);
  50}
  51
  52
  53ssize_t qio_channel_writev_full(QIOChannel *ioc,
  54                                const struct iovec *iov,
  55                                size_t niov,
  56                                int *fds,
  57                                size_t nfds,
  58                                Error **errp)
  59{
  60    QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
  61
  62    if ((fds || nfds) &&
  63        !(ioc->features & (1 << QIO_CHANNEL_FEATURE_FD_PASS))) {
  64        error_setg_errno(errp, EINVAL,
  65                         "Channel does not support file descriptor passing");
  66        return -1;
  67    }
  68
  69    return klass->io_writev(ioc, iov, niov, fds, nfds, errp);
  70}
  71
  72
  73ssize_t qio_channel_readv(QIOChannel *ioc,
  74                          const struct iovec *iov,
  75                          size_t niov,
  76                          Error **errp)
  77{
  78    return qio_channel_readv_full(ioc, iov, niov, NULL, NULL, errp);
  79}
  80
  81
  82ssize_t qio_channel_writev(QIOChannel *ioc,
  83                           const struct iovec *iov,
  84                           size_t niov,
  85                           Error **errp)
  86{
  87    return qio_channel_writev_full(ioc, iov, niov, NULL, 0, errp);
  88}
  89
  90
  91ssize_t qio_channel_read(QIOChannel *ioc,
  92                         char *buf,
  93                         size_t buflen,
  94                         Error **errp)
  95{
  96    struct iovec iov = { .iov_base = buf, .iov_len = buflen };
  97    return qio_channel_readv_full(ioc, &iov, 1, NULL, NULL, errp);
  98}
  99
 100
 101ssize_t qio_channel_write(QIOChannel *ioc,
 102                          const char *buf,
 103                          size_t buflen,
 104                          Error **errp)
 105{
 106    struct iovec iov = { .iov_base = (char *)buf, .iov_len = buflen };
 107    return qio_channel_writev_full(ioc, &iov, 1, NULL, 0, errp);
 108}
 109
 110
 111int qio_channel_set_blocking(QIOChannel *ioc,
 112                              bool enabled,
 113                              Error **errp)
 114{
 115    QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
 116    return klass->io_set_blocking(ioc, enabled, errp);
 117}
 118
 119
 120int qio_channel_close(QIOChannel *ioc,
 121                      Error **errp)
 122{
 123    QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
 124    return klass->io_close(ioc, errp);
 125}
 126
 127
 128GSource *qio_channel_create_watch(QIOChannel *ioc,
 129                                  GIOCondition condition)
 130{
 131    QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
 132    return klass->io_create_watch(ioc, condition);
 133}
 134
 135
 136guint qio_channel_add_watch(QIOChannel *ioc,
 137                            GIOCondition condition,
 138                            QIOChannelFunc func,
 139                            gpointer user_data,
 140                            GDestroyNotify notify)
 141{
 142    GSource *source;
 143    guint id;
 144
 145    source = qio_channel_create_watch(ioc, condition);
 146
 147    g_source_set_callback(source, (GSourceFunc)func, user_data, notify);
 148
 149    id = g_source_attach(source, NULL);
 150    g_source_unref(source);
 151
 152    return id;
 153}
 154
 155
 156int qio_channel_shutdown(QIOChannel *ioc,
 157                         QIOChannelShutdown how,
 158                         Error **errp)
 159{
 160    QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
 161
 162    if (!klass->io_shutdown) {
 163        error_setg(errp, "Data path shutdown not supported");
 164        return -1;
 165    }
 166
 167    return klass->io_shutdown(ioc, how, errp);
 168}
 169
 170
 171void qio_channel_set_delay(QIOChannel *ioc,
 172                           bool enabled)
 173{
 174    QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
 175
 176    if (klass->io_set_delay) {
 177        klass->io_set_delay(ioc, enabled);
 178    }
 179}
 180
 181
 182void qio_channel_set_cork(QIOChannel *ioc,
 183                          bool enabled)
 184{
 185    QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
 186
 187    if (klass->io_set_cork) {
 188        klass->io_set_cork(ioc, enabled);
 189    }
 190}
 191
 192
 193off_t qio_channel_io_seek(QIOChannel *ioc,
 194                          off_t offset,
 195                          int whence,
 196                          Error **errp)
 197{
 198    QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
 199
 200    if (!klass->io_seek) {
 201        error_setg(errp, "Channel does not support random access");
 202        return -1;
 203    }
 204
 205    return klass->io_seek(ioc, offset, whence, errp);
 206}
 207
 208
 209typedef struct QIOChannelYieldData QIOChannelYieldData;
 210struct QIOChannelYieldData {
 211    QIOChannel *ioc;
 212    Coroutine *co;
 213};
 214
 215
 216static gboolean qio_channel_yield_enter(QIOChannel *ioc,
 217                                        GIOCondition condition,
 218                                        gpointer opaque)
 219{
 220    QIOChannelYieldData *data = opaque;
 221    qemu_coroutine_enter(data->co, NULL);
 222    return FALSE;
 223}
 224
 225
 226void coroutine_fn qio_channel_yield(QIOChannel *ioc,
 227                                    GIOCondition condition)
 228{
 229    QIOChannelYieldData data;
 230
 231    assert(qemu_in_coroutine());
 232    data.ioc = ioc;
 233    data.co = qemu_coroutine_self();
 234    qio_channel_add_watch(ioc,
 235                          condition,
 236                          qio_channel_yield_enter,
 237                          &data,
 238                          NULL);
 239    qemu_coroutine_yield();
 240}
 241
 242
 243static gboolean qio_channel_wait_complete(QIOChannel *ioc,
 244                                          GIOCondition condition,
 245                                          gpointer opaque)
 246{
 247    GMainLoop *loop = opaque;
 248
 249    g_main_loop_quit(loop);
 250    return FALSE;
 251}
 252
 253
 254void qio_channel_wait(QIOChannel *ioc,
 255                      GIOCondition condition)
 256{
 257    GMainContext *ctxt = g_main_context_new();
 258    GMainLoop *loop = g_main_loop_new(ctxt, TRUE);
 259    GSource *source;
 260
 261    source = qio_channel_create_watch(ioc, condition);
 262
 263    g_source_set_callback(source,
 264                          (GSourceFunc)qio_channel_wait_complete,
 265                          loop,
 266                          NULL);
 267
 268    g_source_attach(source, ctxt);
 269
 270    g_main_loop_run(loop);
 271
 272    g_source_unref(source);
 273    g_main_loop_unref(loop);
 274    g_main_context_unref(ctxt);
 275}
 276
 277
 278#ifdef _WIN32
 279static void qio_channel_finalize(Object *obj)
 280{
 281    QIOChannel *ioc = QIO_CHANNEL(obj);
 282
 283    if (ioc->event) {
 284        CloseHandle(ioc->event);
 285    }
 286}
 287#endif
 288
 289static const TypeInfo qio_channel_info = {
 290    .parent = TYPE_OBJECT,
 291    .name = TYPE_QIO_CHANNEL,
 292    .instance_size = sizeof(QIOChannel),
 293#ifdef _WIN32
 294    .instance_finalize = qio_channel_finalize,
 295#endif
 296    .abstract = true,
 297    .class_size = sizeof(QIOChannelClass),
 298};
 299
 300
 301static void qio_channel_register_types(void)
 302{
 303    type_register_static(&qio_channel_info);
 304}
 305
 306
 307type_init(qio_channel_register_types);
 308