qemu/chardev/char-io.c
<<
>>
Prefs
   1/*
   2 * QEMU System Emulator
   3 *
   4 * Copyright (c) 2003-2008 Fabrice Bellard
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24#include "qemu/osdep.h"
  25#include "chardev/char-io.h"
  26
  27typedef struct IOWatchPoll {
  28    GSource parent;
  29
  30    QIOChannel *ioc;
  31    GSource *src;
  32
  33    IOCanReadHandler *fd_can_read;
  34    GSourceFunc fd_read;
  35    void *opaque;
  36} IOWatchPoll;
  37
  38static IOWatchPoll *io_watch_poll_from_source(GSource *source)
  39{
  40    return container_of(source, IOWatchPoll, parent);
  41}
  42
  43static gboolean io_watch_poll_prepare(GSource *source,
  44                                      gint *timeout)
  45{
  46    IOWatchPoll *iwp = io_watch_poll_from_source(source);
  47    bool now_active = iwp->fd_can_read(iwp->opaque) > 0;
  48    bool was_active = iwp->src != NULL;
  49    if (was_active == now_active) {
  50        return FALSE;
  51    }
  52
  53    if (now_active) {
  54        iwp->src = qio_channel_create_watch(
  55            iwp->ioc, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL);
  56        g_source_set_callback(iwp->src, iwp->fd_read, iwp->opaque, NULL);
  57        g_source_add_child_source(source, iwp->src);
  58        g_source_unref(iwp->src);
  59    } else {
  60        g_source_remove_child_source(source, iwp->src);
  61        iwp->src = NULL;
  62    }
  63    return FALSE;
  64}
  65
  66static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback,
  67                                       gpointer user_data)
  68{
  69    return G_SOURCE_CONTINUE;
  70}
  71
  72static GSourceFuncs io_watch_poll_funcs = {
  73    .prepare = io_watch_poll_prepare,
  74    .dispatch = io_watch_poll_dispatch,
  75};
  76
  77GSource *io_add_watch_poll(Chardev *chr,
  78                        QIOChannel *ioc,
  79                        IOCanReadHandler *fd_can_read,
  80                        QIOChannelFunc fd_read,
  81                        gpointer user_data,
  82                        GMainContext *context)
  83{
  84    IOWatchPoll *iwp;
  85    char *name;
  86
  87    iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs,
  88                                       sizeof(IOWatchPoll));
  89    iwp->fd_can_read = fd_can_read;
  90    iwp->opaque = user_data;
  91    iwp->ioc = ioc;
  92    iwp->fd_read = (GSourceFunc) fd_read;
  93    iwp->src = NULL;
  94
  95    name = g_strdup_printf("chardev-iowatch-%s", chr->label);
  96    g_source_set_name((GSource *)iwp, name);
  97    g_free(name);
  98
  99    g_source_attach(&iwp->parent, context);
 100    g_source_unref(&iwp->parent);
 101    return (GSource *)iwp;
 102}
 103
 104void remove_fd_in_watch(Chardev *chr)
 105{
 106    if (chr->gsource) {
 107        g_source_destroy(chr->gsource);
 108        chr->gsource = NULL;
 109    }
 110}
 111
 112int io_channel_send_full(QIOChannel *ioc,
 113                         const void *buf, size_t len,
 114                         int *fds, size_t nfds)
 115{
 116    size_t offset = 0;
 117
 118    while (offset < len) {
 119        ssize_t ret = 0;
 120        struct iovec iov = { .iov_base = (char *)buf + offset,
 121                             .iov_len = len - offset };
 122
 123        ret = qio_channel_writev_full(
 124            ioc, &iov, 1,
 125            fds, nfds, NULL);
 126        if (ret == QIO_CHANNEL_ERR_BLOCK) {
 127            if (offset) {
 128                return offset;
 129            }
 130
 131            errno = EAGAIN;
 132            return -1;
 133        } else if (ret < 0) {
 134            errno = EINVAL;
 135            return -1;
 136        }
 137
 138        offset += ret;
 139    }
 140
 141    return offset;
 142}
 143
 144int io_channel_send(QIOChannel *ioc, const void *buf, size_t len)
 145{
 146    return io_channel_send_full(ioc, buf, len, NULL, 0);
 147}
 148