diff options
author | Daniel P. Berrange <berrange@redhat.com> | 2017-08-30 14:53:59 +0100 |
---|---|---|
committer | Daniel P. Berrange <berrange@redhat.com> | 2017-09-05 13:21:58 +0100 |
commit | d4622e55883211072621958d39ddaa73483d201e (patch) | |
tree | b677177e34c985aebca4338a16a29af7b41a5ce1 /io/channel.c | |
parent | 50ea44f07744293b5f503411df8052bf113d8f1d (diff) |
io: add new qio_channel_{readv, writev, read, write}_all functions
These functions wait until they are able to read / write the full
requested data buffer(s).
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Diffstat (limited to 'io/channel.c')
-rw-r--r-- | io/channel.c | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/io/channel.c b/io/channel.c index 1cfb8b33a2..5e8c2f0a91 100644 --- a/io/channel.c +++ b/io/channel.c @@ -22,6 +22,7 @@ #include "io/channel.h" #include "qapi/error.h" #include "qemu/main-loop.h" +#include "qemu/iov.h" bool qio_channel_has_feature(QIOChannel *ioc, QIOChannelFeature feature) @@ -85,6 +86,79 @@ ssize_t qio_channel_writev_full(QIOChannel *ioc, } + +int qio_channel_readv_all(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + Error **errp) +{ + int ret = -1; + struct iovec *local_iov = g_new(struct iovec, niov); + struct iovec *local_iov_head = local_iov; + unsigned int nlocal_iov = niov; + + nlocal_iov = iov_copy(local_iov, nlocal_iov, + iov, niov, + 0, iov_size(iov, niov)); + + while (nlocal_iov > 0) { + ssize_t len; + len = qio_channel_readv(ioc, local_iov, nlocal_iov, errp); + if (len == QIO_CHANNEL_ERR_BLOCK) { + qio_channel_wait(ioc, G_IO_IN); + continue; + } else if (len < 0) { + goto cleanup; + } else if (len == 0) { + error_setg(errp, + "Unexpected end-of-file before all bytes were read"); + goto cleanup; + } + + iov_discard_front(&local_iov, &nlocal_iov, len); + } + + ret = 0; + + cleanup: + g_free(local_iov_head); + return ret; +} + +int qio_channel_writev_all(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + Error **errp) +{ + int ret = -1; + struct iovec *local_iov = g_new(struct iovec, niov); + struct iovec *local_iov_head = local_iov; + unsigned int nlocal_iov = niov; + + nlocal_iov = iov_copy(local_iov, nlocal_iov, + iov, niov, + 0, iov_size(iov, niov)); + + while (nlocal_iov > 0) { + ssize_t len; + len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp); + if (len == QIO_CHANNEL_ERR_BLOCK) { + qio_channel_wait(ioc, G_IO_OUT); + continue; + } + if (len < 0) { + goto cleanup; + } + + iov_discard_front(&local_iov, &nlocal_iov, len); + } + + ret = 0; + cleanup: + g_free(local_iov_head); + return ret; +} + ssize_t qio_channel_readv(QIOChannel *ioc, const struct iovec *iov, size_t niov, @@ -123,6 +197,26 @@ ssize_t qio_channel_write(QIOChannel *ioc, } +int qio_channel_read_all(QIOChannel *ioc, + char *buf, + size_t buflen, + Error **errp) +{ + struct iovec iov = { .iov_base = buf, .iov_len = buflen }; + return qio_channel_readv_all(ioc, &iov, 1, errp); +} + + +int qio_channel_write_all(QIOChannel *ioc, + const char *buf, + size_t buflen, + Error **errp) +{ + struct iovec iov = { .iov_base = (char *)buf, .iov_len = buflen }; + return qio_channel_writev_all(ioc, &iov, 1, errp); +} + + int qio_channel_set_blocking(QIOChannel *ioc, bool enabled, Error **errp) |