From patchwork Sat Mar 10 16:32:30 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Tokarev X-Patchwork-Id: 145866 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 7CAA3B6FA5 for ; Sun, 11 Mar 2012 03:33:57 +1100 (EST) Received: from localhost ([::1]:58344 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S6PEu-0001LG-9X for incoming@patchwork.ozlabs.org; Sat, 10 Mar 2012 11:33:52 -0500 Received: from eggs.gnu.org ([208.118.235.92]:58785) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S6PEB-0008Cz-6S for qemu-devel@nongnu.org; Sat, 10 Mar 2012 11:33:26 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1S6PE7-0006N9-Fm for qemu-devel@nongnu.org; Sat, 10 Mar 2012 11:33:06 -0500 Received: from isrv.corpit.ru ([86.62.121.231]:40413) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S6PE7-0006Mh-4e for qemu-devel@nongnu.org; Sat, 10 Mar 2012 11:33:03 -0500 Received: from gandalf.tls.msk.ru (mjt.vpn.tls.msk.ru [192.168.177.99]) by isrv.corpit.ru (Postfix) with ESMTP id 9CA3BA0751; Sat, 10 Mar 2012 20:33:01 +0400 (MSK) Received: by gandalf.tls.msk.ru (Postfix, from userid 1000) id 936282BB3; Sat, 10 Mar 2012 20:33:00 +0400 (MSK) From: Michael Tokarev To: qemu-devel@nongnu.org Date: Sat, 10 Mar 2012 20:32:30 +0400 Message-Id: <1331397150-25700-6-git-send-email-mjt@msgid.tls.msk.ru> X-Mailer: git-send-email 1.7.9.1 In-Reply-To: <1331397150-25700-1-git-send-email-mjt@tls.msk.ru> References: <1331397150-25700-1-git-send-email-mjt@tls.msk.ru> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 86.62.121.231 Cc: Michael Tokarev Subject: [Qemu-devel] [PATCH 5/5] rewrite and comment qemu_sendv_recvv() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Make it much more understandable, and add comments to it. This is in order to prepare similar function for writev_readv(). The new implementation has been extensively tested by splitting a large buffer into many small randomly-sized chunks, sending it over socket to another, slow process and verifying the receiving data is the same. Signed-off-by: Michael Tokarev --- cutils.c | 119 +++++++++++++++++++++++++++++--------------------------- qemu-common.h | 2 +- 2 files changed, 63 insertions(+), 58 deletions(-) diff --git a/cutils.c b/cutils.c index 6d9175f..e77bbda 100644 --- a/cutils.c +++ b/cutils.c @@ -426,83 +426,88 @@ int qemu_parse_fd(const char *param) * The first `offset' bytes in the iovec buffer are skipped and next * `bytes' bytes are used. */ -int qemu_sendv_recvv(int sockfd, struct iovec *iov, size_t bytes, size_t offset, - bool do_sendv) +int qemu_sendv_recvv(int sockfd, struct iovec *iov, + size_t bytes, size_t offset, bool do_send) { - int ret, iovlen; - size_t diff; - struct iovec *last_iov; - - /* last_iov is inclusive, so count from one. */ - iovlen = 1; - last_iov = iov; - bytes += offset; - - while (last_iov->iov_len < bytes) { - bytes -= last_iov->iov_len; - - last_iov++; - iovlen++; + int ret; + struct iovec *end; + + /* Find the start position, skipping `offset' bytes: + * first, skip all full-sized vector elements, */ + while(offset >= iov->iov_len) { + offset -= iov->iov_len; + ++iov; } - - diff = last_iov->iov_len - bytes; - last_iov->iov_len -= diff; - - while (iov->iov_len <= offset) { - offset -= iov->iov_len; - - iov++; - iovlen--; + if (offset) { + /* second, skip `offset' bytes from the (now) first element, + * undo it on exit */ + iov->iov_base += offset; + iov->iov_len -= offset; + } + /* Find the end position skipping `bytes' bytes: */ + /* first, skip all full-sized elements */ + end = iov; + while(end->iov_len <= bytes) { + bytes -= end->iov_len; + ++end; + } + if (bytes) { + /* second, fixup the last element, and remember + * the length we've cut from the end of it in `bytes' */ + size_t tail = end->iov_len - bytes; + end->iov_len = bytes; + ++end; + bytes = tail; } - - iov->iov_base = (char *) iov->iov_base + offset; - iov->iov_len -= offset; { #if defined CONFIG_IOVEC && defined CONFIG_POSIX struct msghdr msg; memset(&msg, 0, sizeof(msg)); msg.msg_iov = iov; - msg.msg_iovlen = iovlen; - + msg.msg_iovlen = end - iov;; do { - if (do_sendv) { - ret = sendmsg(sockfd, &msg, 0); - } else { - ret = recvmsg(sockfd, &msg, 0); - } - } while (ret == -1 && errno == EINTR); + ret = do_send + ? sendmsg(sockfd, &msg, 0) + : recvmsg(sockfd, &msg, 0); + } while (ret < 0 && errno == EINTR); #else - struct iovec *p = iov; + /* else send piece-by-piece */ + /*XXX Note: windows has WSASend() and WSARecv() */ + struct iovec *p = iov; ret = 0; - while (iovlen > 0) { - int rc; - if (do_sendv) { - rc = send(sockfd, p->iov_base, p->iov_len, 0); - } else { - rc = qemu_recv(sockfd, p->iov_base, p->iov_len, 0); - } - if (rc == -1) { - if (errno == EINTR) { - continue; - } + while(p < end) { + int r = do_send + ? send(sockfd, p->iov_base, p->iov_len, 0) + : qemu_recv(sockfd, p->iov_base, p->iov_len, 0); + if (r > 0) { + ret += r; + ++i; + } else if (!r) { + break; + } else if (errno == EINTR) { + continue; + } else { + /* else it is some "other" error, + * only return if there was no data processed. */ if (ret == 0) { ret = -1; } break; - } - if (rc == 0) { - break; - } - ret += rc; - iovlen--, p++; + } } #endif } /* Undo the changes above */ - iov->iov_base = (char *) iov->iov_base - offset; - iov->iov_len += offset; - last_iov->iov_len += diff; + if (offset) { + iov->iov_base -= offset; + iov->iov_len += offset; + } + if (bytes) { + --end; + end->iov_len += bytes; + } + return ret; } diff --git a/qemu-common.h b/qemu-common.h index 2bf630d..17d5321 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -206,7 +206,7 @@ int qemu_pipe(int pipefd[2]); * the beginning of iovec but at byte position `offset'. */ int qemu_sendv_recvv(int sockfd, struct iovec *iov, - size_t bytes, size_t offset, bool do_sendv); + size_t bytes, size_t offset, bool do_send); #define qemu_recvv(sockfd, iov, bytes, offset) \ qemu_sendv_recvv(sockfd, iov, bytes, offset, false) #define qemu_sendv(sockfd, iov, bytes, offset) \