Advanced File I/O - readv() example (
Page 4 of 4 )
Now, let’s consider an example program that uses the readv() system call to read from the previously generated text file using vectored I/O. This self-contained exam
ple is likewise simple yet complete:
#include <stdio.h
>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/uio.h>
int main ()
{
char foo[48], bar[51], baz[49];
struct iovec iov[3];
ssize_t nr;
int fd, i;
fd = open ("buccaneer.txt", O_RDONLY);
if (fd == -1) {
perror ("open");
return 1;
}
/* set up our iovec structures */
iov[0].iov_base = foo;
iov[0].iov_len = sizeof (foo);
iov[1].iov_base = bar;
iov[1].iov_len = sizeof (bar);
iov[2].iov_base = baz;
iov[2].iov_len = sizeof (baz);
/* read into the structures with a single call */
nr = readv (fd, iov, 3);
if (nr == -1) {
perror ("readv");
return 1;
}
for (i = 0; i < 3; i++)
printf ("%d: %s", i, (char *) iov[i].iov_base);
if (close (fd)) {
perror ("close");
return 1;
}
return 0;
}
Running this program after running the previous program produces the following results:
$ ./readv
0: The term buccaneer comes from the word boucan.
1: A boucan is a wooden frame used for cooking meat.
2: Buccaneer is the West Indies name for a pirate.
Implementation
A naïve implementation of readv() and
writev()
could be done in user space as a simple loop, something similar to the following:
#include <unistd.h>
#include <sys/uio.h>
ssize_t naive_writev (int fd, const struct iovec *iov, int count)
{
ssize_t ret = 0;
int i;
for (i = 0; i < count; i++) {
ssize_t nr;
nr = write (fd, iov[i].iov_base, iov[i].iov_len);
if (nr == -1) {
ret = -1;
break;
}
ret += nr;
}
return ret;
}
Thankfully, this is not the Linux implementation: Linux implements
readv()
and
writev()
as system calls, and internally performs scatter/gather I/O. In fact, all I/O inside the Linux kernel is vectored;
read()
and
write()
are implemented as vectored I/O with a vector of only one segment.
Please check back next week for the continuation of this article.