From c953ad4edff1bb64fb54124bfec7c3726cb2865a Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Fri, 23 Dec 2011 18:28:45 +0100 Subject: [PATCH] Introduce xwritev(). For the sideband API we will need to write two buffers one after another. This patch adds the new public function xwritev() to fd.c which takes an arbitrary number of buffers and calls writev() to perform the write. With this function in place, xwrite() becomes a trivial wrapper for xwritev(). --- fd.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++------------ fd.h | 1 + 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/fd.c b/fd.c index a73325ba..d2f93611 100644 --- a/fd.c +++ b/fd.c @@ -19,32 +19,56 @@ #include "fd.h" /** - * Write a buffer to a file descriptor, re-writing on short writes. + * Write an array of buffers to a file descriptor. * * \param fd The file descriptor. - * \param buf The buffer to write. - * \param len The number of bytes to write. + * \param iov Pointer to one or more buffers. + * \param iovcnt The number of buffers. * * EAGAIN/EWOULDBLOCK is not considered a fatal error condition. For example * DCCP CCID3 has a sending wait queue which fills up and is emptied * asynchronously. The EAGAIN case means that there is currently no space in * the wait queue, but this can change at any moment. * - * \return Negative on fatal errors, number of bytes written else. For blocking - * file descriptors this function returns either \a len or the error code of - * the fatal error that caused the last write call to fail. For nonblocking - * file descriptors there is a third possibility: A positive return value < \a - * len indicates that some bytes have been written but the next write would - * block. + * \return Negative on fatal errors, number of bytes written else. + * + * For blocking file descriptors, this function returns either the sum of all + * buffer sizes, or the error code of the fatal error that caused the last + * write call to fail. + * + * For nonblocking file descriptors there is a third possibility: Any positive + * return value less than the sum of the buffer sizes indicates that some bytes + * have been written but the next write would block. + * + * \sa writev(2), \ref xwrite(). */ -int xwrite(int fd, const char *buf, size_t len) +int xwritev(int fd, struct iovec *iov, int iovcnt) { size_t written = 0; - - while (written < len) { - ssize_t ret = write(fd, buf + written, len - written); + int i; + struct iovec saved_iov, *curiov; + + i = 0; + curiov = iov; + saved_iov = *curiov; + while (i < iovcnt && curiov->iov_len > 0) { + ssize_t ret = writev(fd, curiov, iovcnt - i); if (ret >= 0) { written += ret; + while (ret > 0) { + if (ret < curiov->iov_len) { + curiov->iov_base += ret; + curiov->iov_len -= ret; + break; + } + ret -= curiov->iov_len; + *curiov = saved_iov; + i++; + if (i >= iovcnt) + return written; + curiov++; + saved_iov = *curiov; + } continue; } if (errno == EINTR) @@ -66,6 +90,23 @@ int xwrite(int fd, const char *buf, size_t len) return written; } +/** + * Write a buffer to a file descriptor, re-writing on short writes. + * + * \param fd The file descriptor. + * \param buf The buffer to write. + * \param len The number of bytes to write. + * + * This is a simple wrapper for \ref xwritev(). + * + * \return The return value of the underlying call to \ref xwritev(). + */ +int xwrite(int fd, const char *buf, size_t len) +{ + struct iovec iov = {.iov_base = (void *)buf, .iov_len = len}; + return xwritev(fd, &iov, 1); +} + /** * Write all data to a file descriptor. * diff --git a/fd.h b/fd.h index b8356edd..30b3411b 100644 --- a/fd.h +++ b/fd.h @@ -30,6 +30,7 @@ int readv_nonblock(int fd, struct iovec *iov, int iovcnt, fd_set *rfds, int read_nonblock(int fd, void *buf, size_t sz, fd_set *rfds, size_t *num_bytes); int read_pattern(int fd, const char *pattern, size_t bufsize, fd_set *rfds); int xwrite(int fd, const char *buf, size_t len); +int xwritev(int fd, struct iovec *iov, int iovcnt); int for_each_file_in_dir(const char *dirname, int (*func)(const char *, void *), void *private_data); /** -- 2.39.5