Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Techniques for handling short reads/writes with scatter-gather?

Tags:

c

linux

unix

Scatter-gather - readv()/writev()/preadv()/pwritev() - reads/writes a variable number of iovec structs in a single system call. Basically it reads/write each buffer sequentially from the 0th iovec to the Nth. However according to the documentation it can also return less on the readv/writev calls than was requested. I was wondering if there is a standard/best practice/elegant way to handle that situation.

If we are just handling a bunch of character buffers or similar this isn't a big deal. But one of the niceties is using scatter-gather for structs and/or discrete variables as the individual iovec items. How do you handle the situation where the readv/writev only reads/writes a portion of a struct or half of a long or something like that.

Below is some contrived code of what I am getting at:

int fd;

struct iovec iov[3];

long aLong = 74775767;
int  aInt  = 949;
char aBuff[100];  //filled from where ever

ssize_t bytesWritten = 0;
ssize_t bytesToWrite = 0;

iov[0].iov_base = &aLong;
iov[0].iov_len = sizeof(aLong);
bytesToWrite += iov[0].iov_len;

iov[1].iov_base = &aInt;
iov[1].iov_len = sizeof(aInt);
bytesToWrite += iov[1].iov_len;

iov[2].iov_base = &aBuff;
iov[2].iov_len = sizeof(aBuff);
bytesToWrite += iov[2].iov_len;

bytesWritten = writev(fd, iov, 3);

if (bytesWritten == -1)
{
    //handle error
}

if (bytesWritten < bytesToWrite)
    //how to gracefully continue?.........
like image 614
ValenceElectron Avatar asked May 02 '11 05:05

ValenceElectron


People also ask

What is Readv and Writev?

The readv() system call reads iovcnt buffers from the file associated with the file descriptor fd into the buffers described by iov ("scatter input"). The writev() system call writes iovcnt buffers of data described by iov to the file associated with the file descriptor fd ("gather output").

What is an Iovec?

Data Type: struct iovec. The iovec structure describes a buffer. It contains two fields: void *iov_base. Contains the address of a buffer.

What is Readv?

The readv() function reads data from a file or a socket with descriptor fs and stores it in a set of buffers. The data is scattered into the buffers specified by iov[0]… iov[iovcnt-1]. Parameter Description fs. The file or socket descriptor.

What is Iovec in Linux?

The struct iovec defines one vector element. Normally, this structure is used as an array of multiple elements. For each transfer element, the pointer member iov_base points to a buffer that is receiving data for readv or is transmitting data for writev.


1 Answers

Use a loop like the following to advance the partially-processed iov:

for (;;) {
    written = writev(fd, iov+cur, count-cur);
    if (written < 0) goto error;
    while (cur < count && written >= iov[cur].iov_len)
        written -= iov[cur++].iov_len;
    if (cur == count) break;
    iov[cur].iov_base = (char *)iov[cur].iov_base + written;
    iov[cur].iov_len -= written;
}

Note that if you don't check for cur < count you will read past the end of iov which might contain zero.

like image 161
R.. GitHub STOP HELPING ICE Avatar answered Oct 18 '22 11:10

R.. GitHub STOP HELPING ICE