From: www.itworld.com

Scatter/Gather I/O

by Danny Kalev

June 14, 2002 —

 

The classic read() and write() sycalls enable you to handle a single
buffer at a time. The problem is that applications often need to write
various data types to a contiguous region of a file. Although you can
use multiple write() calls to accomplish that, this isn't an atomic
operation; another thread might access the same file region between
every pair of write() calls. As a workaround, you can pack all the data
into a single buffer before writing it to a file. However, the
performance overhead incurred by copying numerous memory blocks is
noticeable.

Scatter/Gather Read and Write
The readv() and writev() solve this problem easily. Instead of handling
a single data buffer at a time, they take an array of records, each of
which represents a distinct buffer. These buffers are read from or
written to in the same order that they are listed in the array. More
importantly, the writev() and readv() calls are atomic.

readv() and writev() are called "scatter and gather read and write"
because readv() scatters data from various sources across memory and
writev() gathers data from various memory addresses. These functions are
declared as follows:

int readv(int fd, const struct iovec* vec, size_t count);
int writev(int fd, const struct iovec* vec, size_t count);

The first argument is the file descriptor to be read from or written to.
The second argument is a pointer to one or more structs of type iovec,
which represents a data buffer. The third argument is the number of
iovec structs passed in vec. Struct iovec is declared as follows:

struct iovec{
void * iov_base; /*buffer's address*/
size_t iov_len; /*buffer's size in bytes*/
};

The return value of both functions is the total number of bytes read or
written.

Example
The following program gathers three buffers (strings, in this case) and
outputs them using a single writev() call. The result is displayed on
the standard output:

#include
int main
{
iovec vecs[3];
vecs[0].iov_base="first";
vecs[0].iov_len=5;

vecs[1].iov_base=" second ";
vecs[1].iov_len=8;

vecs[2].iov_base="last\n";
vecs[2].iov_len=5;
writev(1, vecs, 3); /*1 is equal to stdout*/
}