mirror of
https://github.com/qemu/qemu.git
synced 2024-11-30 07:13:38 +08:00
e0622ae3ca
There is no "version 2" of the "Lesser" General Public License. It is either "GPL version 2.0" or "Lesser GPL version 2.1". This patch replaces all occurrences of "Lesser GPL version 2" with "Lesser GPL version 2.1" in comment section. Signed-off-by: Chetan Pant <chetan4windows@gmail.com> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
252 lines
7.0 KiB
C
252 lines
7.0 KiB
C
/*
|
|
* 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,
|
|
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,
|
|
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);
|