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