123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- /*
- * QEMU I/O channels memory buffer driver
- *
- * Copyright (c) 2015 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- */
- #include "qemu/osdep.h"
- #include "io/channel-buffer.h"
- #include "io/channel-watch.h"
- #include "qemu/module.h"
- #include "qemu/sockets.h"
- #include "trace.h"
- QIOChannelBuffer *
- qio_channel_buffer_new(size_t capacity)
- {
- QIOChannelBuffer *ioc;
- ioc = QIO_CHANNEL_BUFFER(object_new(TYPE_QIO_CHANNEL_BUFFER));
- if (capacity) {
- ioc->data = g_new0(uint8_t, capacity);
- ioc->capacity = capacity;
- }
- return ioc;
- }
- static void qio_channel_buffer_finalize(Object *obj)
- {
- QIOChannelBuffer *ioc = QIO_CHANNEL_BUFFER(obj);
- g_free(ioc->data);
- ioc->capacity = ioc->usage = ioc->offset = 0;
- }
- static ssize_t qio_channel_buffer_readv(QIOChannel *ioc,
- const struct iovec *iov,
- size_t niov,
- int **fds,
- size_t *nfds,
- int flags,
- Error **errp)
- {
- QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc);
- ssize_t ret = 0;
- size_t i;
- for (i = 0; i < niov; i++) {
- size_t want = iov[i].iov_len;
- if (bioc->offset >= bioc->usage) {
- break;
- }
- if ((bioc->offset + want) > bioc->usage) {
- want = bioc->usage - bioc->offset;
- }
- memcpy(iov[i].iov_base, bioc->data + bioc->offset, want);
- ret += want;
- bioc->offset += want;
- }
- return ret;
- }
- static ssize_t qio_channel_buffer_writev(QIOChannel *ioc,
- const struct iovec *iov,
- size_t niov,
- int *fds,
- size_t nfds,
- int flags,
- Error **errp)
- {
- QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc);
- ssize_t ret = 0;
- size_t i;
- size_t towrite = 0;
- for (i = 0; i < niov; i++) {
- towrite += iov[i].iov_len;
- }
- if ((bioc->offset + towrite) > bioc->capacity) {
- bioc->capacity = bioc->offset + towrite;
- bioc->data = g_realloc(bioc->data, bioc->capacity);
- }
- if (bioc->offset > bioc->usage) {
- memset(bioc->data, 0, bioc->offset - bioc->usage);
- bioc->usage = bioc->offset;
- }
- for (i = 0; i < niov; i++) {
- memcpy(bioc->data + bioc->usage,
- iov[i].iov_base,
- iov[i].iov_len);
- bioc->usage += iov[i].iov_len;
- bioc->offset += iov[i].iov_len;
- ret += iov[i].iov_len;
- }
- return ret;
- }
- static int qio_channel_buffer_set_blocking(QIOChannel *ioc G_GNUC_UNUSED,
- bool enabled G_GNUC_UNUSED,
- Error **errp G_GNUC_UNUSED)
- {
- return 0;
- }
- static off_t qio_channel_buffer_seek(QIOChannel *ioc,
- off_t offset,
- int whence,
- Error **errp)
- {
- QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc);
- bioc->offset = offset;
- return offset;
- }
- static int qio_channel_buffer_close(QIOChannel *ioc,
- Error **errp)
- {
- QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc);
- g_free(bioc->data);
- bioc->data = NULL;
- bioc->capacity = bioc->usage = bioc->offset = 0;
- return 0;
- }
- typedef struct QIOChannelBufferSource QIOChannelBufferSource;
- struct QIOChannelBufferSource {
- GSource parent;
- QIOChannelBuffer *bioc;
- GIOCondition condition;
- };
- static gboolean
- qio_channel_buffer_source_prepare(GSource *source,
- gint *timeout)
- {
- QIOChannelBufferSource *bsource = (QIOChannelBufferSource *)source;
- *timeout = -1;
- return (G_IO_IN | G_IO_OUT) & bsource->condition;
- }
- static gboolean
- qio_channel_buffer_source_check(GSource *source)
- {
- QIOChannelBufferSource *bsource = (QIOChannelBufferSource *)source;
- return (G_IO_IN | G_IO_OUT) & bsource->condition;
- }
- static gboolean
- qio_channel_buffer_source_dispatch(GSource *source,
- GSourceFunc callback,
- gpointer user_data)
- {
- QIOChannelFunc func = (QIOChannelFunc)callback;
- QIOChannelBufferSource *bsource = (QIOChannelBufferSource *)source;
- return (*func)(QIO_CHANNEL(bsource->bioc),
- ((G_IO_IN | G_IO_OUT) & bsource->condition),
- user_data);
- }
- static void
- qio_channel_buffer_source_finalize(GSource *source)
- {
- QIOChannelBufferSource *ssource = (QIOChannelBufferSource *)source;
- object_unref(OBJECT(ssource->bioc));
- }
- GSourceFuncs qio_channel_buffer_source_funcs = {
- qio_channel_buffer_source_prepare,
- qio_channel_buffer_source_check,
- qio_channel_buffer_source_dispatch,
- qio_channel_buffer_source_finalize
- };
- static GSource *qio_channel_buffer_create_watch(QIOChannel *ioc,
- GIOCondition condition)
- {
- QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc);
- QIOChannelBufferSource *ssource;
- GSource *source;
- source = g_source_new(&qio_channel_buffer_source_funcs,
- sizeof(QIOChannelBufferSource));
- ssource = (QIOChannelBufferSource *)source;
- ssource->bioc = bioc;
- object_ref(OBJECT(bioc));
- ssource->condition = condition;
- return source;
- }
- static void qio_channel_buffer_class_init(ObjectClass *klass,
- void *class_data G_GNUC_UNUSED)
- {
- QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
- ioc_klass->io_writev = qio_channel_buffer_writev;
- ioc_klass->io_readv = qio_channel_buffer_readv;
- ioc_klass->io_set_blocking = qio_channel_buffer_set_blocking;
- ioc_klass->io_seek = qio_channel_buffer_seek;
- ioc_klass->io_close = qio_channel_buffer_close;
- ioc_klass->io_create_watch = qio_channel_buffer_create_watch;
- }
- static const TypeInfo qio_channel_buffer_info = {
- .parent = TYPE_QIO_CHANNEL,
- .name = TYPE_QIO_CHANNEL_BUFFER,
- .instance_size = sizeof(QIOChannelBuffer),
- .instance_finalize = qio_channel_buffer_finalize,
- .class_init = qio_channel_buffer_class_init,
- };
- static void qio_channel_buffer_register_types(void)
- {
- type_register_static(&qio_channel_buffer_info);
- }
- type_init(qio_channel_buffer_register_types);
|