[comp.unix.programmer] readv/writev

jwb@cepmax.ncsu.edu (John W. Baugh Jr.) (06/22/91)

Stevens (in Unix Network Programming) notes that read/write on a
socket may input/output fewer bytes than requested.  Can I expect the
same behavior for readv/writev?  If so, how might one implement
"readvn"/"writevn"? (a la Steven's readn/writen)

John Baugh
jwb@cepmax.ncsu.edu

torek@elf.ee.lbl.gov (Chris Torek) (06/24/91)

In article <1991Jun21.215941.5693@ncsu.edu> jwb@cepmax.ncsu.edu writes:
>Stevens (in Unix Network Programming) notes that read/write on a
>socket may input/output fewer bytes than requested.  Can I expect the
>same behavior for readv/writev?

Yes.

>If so, how might one implement "readvn"/"writevn"? (a la Steven's ...)

(I am guessing what these are: loops around the read/write calls.)
It is ugly.  You must make use of the fact that the if the system
call returns `early', it has partially processed at most one vector
(and fully processed only any earlier vectors).  Thus, something like:

	cc = readv(fd, iov, iovcnt);
	if (cc == 0) ... handle EOF ...;
	if (cc < 0) ... handle error ...;
	for (p = iov, n = iovcnt; n > 0; p++, n--) {
		if (iov->iov_len > cc) {
			iov->iov_base += cc;
			iov->iov_len -= cc;
			break;
		}
		cc -= iov->iov_len;
	}
	if (cc == 0) ... all done ...;
	iov = p;
	iovcnt = n;
	/* now there are iovcnt io vectors undone */

Note that this may modify one of the I/O vectors, hence is not
suitable in some cases.  To be fully general this would have to
copy the vectors in those cases, and work from the copies; then
it would have to free the copies when the whole transfer is done.

This is one reason I elected to ignore readv and writev in my
4BSD stdio rewrite.
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427)
Berkeley, CA		Domain:	torek@ee.lbl.gov

rsalz@bbn.com (Rich Salz) (06/26/91)

In <1991Jun21.215941.5693@ncsu.edu> jwb@cepmax.ncsu.edu writes:
>Stevens (in Unix Network Programming) notes that read/write on a
>socket may input/output fewer bytes than requested.  Can I expect the
>same behavior for readv/writev?  If so, how might one implement
>"readvn"/"writevn"? (a la Steven's readn/writen)

I assume you want something like this:

/*
**  Handling the return value of writev is a pain.  It should return
**  the number of iov's it fully wrote out, and update the fields
**  in all of them to contain the new startpoints.
*/
int
bigwritev(fd, vp, vpcount)
    int			fd;
    struct iovec	*vp;
    register int	vpcount;
{
    register int	i;
    register long	left;

    /* Get the total bytecount. */
    for (left = 0, i = vpcount; --i >= 0; )
	left += vp[i].iov_len;

    while (vpcount) {
	if ((i = writev(fd, vp, vpcount)) < 0)
	    return -1;
	if ((left -= i) <= 0)
	    break;
	for (; i >= vp->iov_len; vp++, vpcount--)
	    i -= vp->iov_len;
	vp->iov_base += i;
	vp->iov_len -= i;
    }
    return 0;
}

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.

torek@elf.ee.lbl.gov (Chris Torek) (06/26/91)

In article <14609@dog.ee.lbl.gov> I wrote:
>	for (p = iov, n = iovcnt; n > 0; p++, n--) {
>		if (iov->iov_len > cc) {
[etc]

All the `iov->'s in the loop should be `p->'s.
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427)
Berkeley, CA		Domain:	torek@ee.lbl.gov