Advanced File I/O - Scatter/Gather I/O (
Page 2 of 4 )
Scatter/gather I/O is a method of input and output where a single system call writes to a vector of buffers from a single data stream, or, alternatively, reads into a vector of buffers from a single data stream. This type of I/O is so named because the data is scattered into or gathered from the given vector of buffers. An alternative name for this approach to input and output is vectored I/O. In comparison, the standard read and write system calls that we covered in Chapter 2 provide linear I/O.
Scatter/gather I/O provides several advantages over linear I/O methods:
More natural handling
If your data is naturally segmented—say, the fields of a predefined header file—vectored I/O allows for intuitive manipulation.
Efficiency
A single vectored I/O operation can replace multiple linear I/O operations.
Performance
In addition to a reduction in the number of issued system calls, a vectored I/O implementation can provide improved performance over a linear I/O implementation via internal optimizations.
Atomicity
Unlike with multiple linear I/O operations, a process can execute a single vectored I/O operation with no risk of interleaving of an operation from another process.
Both a more natural I/O method and atomicity are achievable without a scatter/gather I/O mechanism. A process can concatenate the disjoint vectors into a single buffer before writing, and decompose the returned buffer into multiple vectors after reading—that is, a user-space application can perform the scattering and the gathering manually. Such a solution, however, is neither efficient nor fun to implement.
readv( ) and writev( )
POSIX 1003.1-2001 defines, and Linux implements, a pair of system calls that implement scatter/gather I/O. The Linux implementation satisfies all of the goals listed in the previous section.
The
readv()
function reads
count
segments from the file descriptor
fd
into the buffers described by
iov
:
#include <sys/uio.h>
ssize_t readv (int fd,
const struct iovec *iov,
int count);
The writev()
function writes at most
count
segments from the buffers described by
iov
into the file descriptor
fd
:
#include <sys/uio.h>
ssize_t writev (int fd,
const struct iovec *iov,
int count);
The readv() and writev()
functions behave the same as
read()
and
write()
, respec
tively, except that multiple buffers are read from or written to.
Each
iovec
structure describes an independent disjoint buffer, which is called a segment:
#include <sys/uio.h>
struct iovec {
void *iov_base; /* pointer to start of buffer */
size_t iov_len; /* size of buffer in bytes */
};
A set of segments is called a vector. Each segment in the vector describes the address and length of a buffer in memory to or from which data should be written or read. The readv()
function fills each buffer of
iov_len
bytes completely before proceeding to the next buffer. The
writev()
function always writes out all full
iov_len
bytes before proceeding to the next buffer. Both functions always operate on the segments in order, starting with
iov[0]
, then
iov[1]
, and so on, through
iov[count–1]
.