qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

channel-buffer.c (7190B)


      1 /*
      2  * QEMU I/O channels memory buffer driver
      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-buffer.h"
     23 #include "io/channel-watch.h"
     24 #include "qemu/module.h"
     25 #include "qemu/sockets.h"
     26 #include "trace.h"
     27 
     28 QIOChannelBuffer *
     29 qio_channel_buffer_new(size_t capacity)
     30 {
     31     QIOChannelBuffer *ioc;
     32 
     33     ioc = QIO_CHANNEL_BUFFER(object_new(TYPE_QIO_CHANNEL_BUFFER));
     34 
     35     if (capacity) {
     36         ioc->data = g_new0(uint8_t, capacity);
     37         ioc->capacity = capacity;
     38     }
     39 
     40     return ioc;
     41 }
     42 
     43 
     44 static void qio_channel_buffer_finalize(Object *obj)
     45 {
     46     QIOChannelBuffer *ioc = QIO_CHANNEL_BUFFER(obj);
     47     g_free(ioc->data);
     48     ioc->capacity = ioc->usage = ioc->offset = 0;
     49 }
     50 
     51 
     52 static ssize_t qio_channel_buffer_readv(QIOChannel *ioc,
     53                                         const struct iovec *iov,
     54                                         size_t niov,
     55                                         int **fds,
     56                                         size_t *nfds,
     57                                         Error **errp)
     58 {
     59     QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc);
     60     ssize_t ret = 0;
     61     size_t i;
     62 
     63     for (i = 0; i < niov; i++) {
     64         size_t want = iov[i].iov_len;
     65         if (bioc->offset >= bioc->usage) {
     66             break;
     67         }
     68         if ((bioc->offset + want) > bioc->usage)  {
     69             want = bioc->usage - bioc->offset;
     70         }
     71         memcpy(iov[i].iov_base, bioc->data + bioc->offset, want);
     72         ret += want;
     73         bioc->offset += want;
     74     }
     75 
     76     return ret;
     77 }
     78 
     79 static ssize_t qio_channel_buffer_writev(QIOChannel *ioc,
     80                                          const struct iovec *iov,
     81                                          size_t niov,
     82                                          int *fds,
     83                                          size_t nfds,
     84                                          int flags,
     85                                          Error **errp)
     86 {
     87     QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc);
     88     ssize_t ret = 0;
     89     size_t i;
     90     size_t towrite = 0;
     91 
     92     for (i = 0; i < niov; i++) {
     93         towrite += iov[i].iov_len;
     94     }
     95 
     96     if ((bioc->offset + towrite) > bioc->capacity) {
     97         bioc->capacity = bioc->offset + towrite;
     98         bioc->data = g_realloc(bioc->data, bioc->capacity);
     99     }
    100 
    101     if (bioc->offset > bioc->usage) {
    102         memset(bioc->data, 0, bioc->offset - bioc->usage);
    103         bioc->usage = bioc->offset;
    104     }
    105 
    106     for (i = 0; i < niov; i++) {
    107         memcpy(bioc->data + bioc->usage,
    108                iov[i].iov_base,
    109                iov[i].iov_len);
    110         bioc->usage += iov[i].iov_len;
    111         bioc->offset += iov[i].iov_len;
    112         ret += iov[i].iov_len;
    113     }
    114 
    115     return ret;
    116 }
    117 
    118 static int qio_channel_buffer_set_blocking(QIOChannel *ioc G_GNUC_UNUSED,
    119                                            bool enabled G_GNUC_UNUSED,
    120                                            Error **errp G_GNUC_UNUSED)
    121 {
    122     return 0;
    123 }
    124 
    125 
    126 static off_t qio_channel_buffer_seek(QIOChannel *ioc,
    127                                      off_t offset,
    128                                      int whence,
    129                                      Error **errp)
    130 {
    131     QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc);
    132 
    133     bioc->offset = offset;
    134 
    135     return offset;
    136 }
    137 
    138 
    139 static int qio_channel_buffer_close(QIOChannel *ioc,
    140                                     Error **errp)
    141 {
    142     QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc);
    143 
    144     g_free(bioc->data);
    145     bioc->data = NULL;
    146     bioc->capacity = bioc->usage = bioc->offset = 0;
    147 
    148     return 0;
    149 }
    150 
    151 
    152 typedef struct QIOChannelBufferSource QIOChannelBufferSource;
    153 struct QIOChannelBufferSource {
    154     GSource parent;
    155     QIOChannelBuffer *bioc;
    156     GIOCondition condition;
    157 };
    158 
    159 static gboolean
    160 qio_channel_buffer_source_prepare(GSource *source,
    161                                   gint *timeout)
    162 {
    163     QIOChannelBufferSource *bsource = (QIOChannelBufferSource *)source;
    164 
    165     *timeout = -1;
    166 
    167     return (G_IO_IN | G_IO_OUT) & bsource->condition;
    168 }
    169 
    170 static gboolean
    171 qio_channel_buffer_source_check(GSource *source)
    172 {
    173     QIOChannelBufferSource *bsource = (QIOChannelBufferSource *)source;
    174 
    175     return (G_IO_IN | G_IO_OUT) & bsource->condition;
    176 }
    177 
    178 static gboolean
    179 qio_channel_buffer_source_dispatch(GSource *source,
    180                                    GSourceFunc callback,
    181                                    gpointer user_data)
    182 {
    183     QIOChannelFunc func = (QIOChannelFunc)callback;
    184     QIOChannelBufferSource *bsource = (QIOChannelBufferSource *)source;
    185 
    186     return (*func)(QIO_CHANNEL(bsource->bioc),
    187                    ((G_IO_IN | G_IO_OUT) & bsource->condition),
    188                    user_data);
    189 }
    190 
    191 static void
    192 qio_channel_buffer_source_finalize(GSource *source)
    193 {
    194     QIOChannelBufferSource *ssource = (QIOChannelBufferSource *)source;
    195 
    196     object_unref(OBJECT(ssource->bioc));
    197 }
    198 
    199 GSourceFuncs qio_channel_buffer_source_funcs = {
    200     qio_channel_buffer_source_prepare,
    201     qio_channel_buffer_source_check,
    202     qio_channel_buffer_source_dispatch,
    203     qio_channel_buffer_source_finalize
    204 };
    205 
    206 static GSource *qio_channel_buffer_create_watch(QIOChannel *ioc,
    207                                                 GIOCondition condition)
    208 {
    209     QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc);
    210     QIOChannelBufferSource *ssource;
    211     GSource *source;
    212 
    213     source = g_source_new(&qio_channel_buffer_source_funcs,
    214                           sizeof(QIOChannelBufferSource));
    215     ssource = (QIOChannelBufferSource *)source;
    216 
    217     ssource->bioc = bioc;
    218     object_ref(OBJECT(bioc));
    219 
    220     ssource->condition = condition;
    221 
    222     return source;
    223 }
    224 
    225 
    226 static void qio_channel_buffer_class_init(ObjectClass *klass,
    227                                           void *class_data G_GNUC_UNUSED)
    228 {
    229     QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
    230 
    231     ioc_klass->io_writev = qio_channel_buffer_writev;
    232     ioc_klass->io_readv = qio_channel_buffer_readv;
    233     ioc_klass->io_set_blocking = qio_channel_buffer_set_blocking;
    234     ioc_klass->io_seek = qio_channel_buffer_seek;
    235     ioc_klass->io_close = qio_channel_buffer_close;
    236     ioc_klass->io_create_watch = qio_channel_buffer_create_watch;
    237 }
    238 
    239 static const TypeInfo qio_channel_buffer_info = {
    240     .parent = TYPE_QIO_CHANNEL,
    241     .name = TYPE_QIO_CHANNEL_BUFFER,
    242     .instance_size = sizeof(QIOChannelBuffer),
    243     .instance_finalize = qio_channel_buffer_finalize,
    244     .class_init = qio_channel_buffer_class_init,
    245 };
    246 
    247 static void qio_channel_buffer_register_types(void)
    248 {
    249     type_register_static(&qio_channel_buffer_info);
    250 }
    251 
    252 type_init(qio_channel_buffer_register_types);