This appendix contains sample code (Listing A-1) that demonstrates how to use mmap
and munmap
to simulate a large address space using offsets into a file.
Listing A-1 Using mmap
and munmap
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <fcntl.h> |
#include <errno.h> |
#include <sys/stat.h> |
#include <sys/types.h> |
#include <sys/mman.h> |
/* |
* max_mmap_size(filename) |
* A not-so-great attempt to determine at run time how much |
* of a given file can be mapped in. Usually, the amount will |
* be the minimum of filesize or 0x7fffffff. The math is a |
* wee bit off on the binary search. |
*/ |
size_t |
max_mmap_size(const char *file) { |
int fd; |
struct stat sbuf; |
size_t retval; |
off_t min = 0, max = (size_t)(~0); |
fd = open(file, O_RDONLY); |
if (fd == -1) |
return 0; |
fstat(fd, &sbuf); |
if ((sbuf.st_mode & S_IFMT) != S_IFREG) { |
close(fd); |
return 0; |
} else if ((off_t)max > sbuf.st_size) |
max = (sbuf.st_size); |
retval = (size_t)((max + min) / 2); |
while (min != max) { |
caddr_t t; |
errno = 0; |
t = mmap(0, retval, PROT_READ, MAP_SHARED, fd, 0); |
if (t == (caddr_t)-1 && errno != 0) { |
if (errno != EINVAL) |
return 0; |
/* too large */ |
max = retval - 1; |
} else { |
min = retval + 1; |
} |
munmap(t, retval); |
retval = (size_t)((min + max) / 2); |
} |
close(fd); |
return (size_t)min - 1; |
} |
/* |
* sum(filename, starting_offset, size) |
* Sum the bytes in the file specified by the <filename> parameter, |
* starting at the specified offset and continuing for <size> bytes. |
* This is very slow, but this function will eventually touch |
* every byte of the file segment you have asked for. |
*/ |
long long |
sum(const char *file, off_t offset, size_t count) { |
long long retval = 0; |
struct stat sbuf; |
int fd; |
caddr_t t; |
char *cp; |
fd = open(file, O_RDONLY); |
if (fd == -1) { |
return -1LL; |
} |
fstat(fd, &sbuf); |
if (offset > sbuf.st_size) |
return -1; |
sbuf.st_size -= offset; |
if (sbuf.st_size < count) |
count = sbuf.st_size; |
if (count == 0) { |
retval = -1LL; |
goto out; |
} |
errno = 0; |
fprintf(stderr, "mmap(NULL, %u, PROT_READ, MAP_FILE|MAP_SHARED, %d, %qu)\n", |
count, fd, offset); |
t = mmap(NULL, count, PROT_READ, MAP_FILE|MAP_SHARED, fd, offset); |
if (t == (caddr_t)-1 && errno != 0) { |
fprintf(stderr, "cannot mmap %s: %s\n", file, strerror(errno)); |
retval = -1LL; |
goto out; |
} |
for (cp = t; cp < &t[count]; cp++) |
retval += *cp; |
munmap(t, count); |
out: |
close(fd); |
return retval; |
} |
main(int ac, char **av) { |
size_t max; |
long long s = 0; |
long long t, off = 0; |
if (ac != 2) { |
fprintf(stderr, "usage: %s <filename>\n", av[0]); |
exit(1); |
} |
max = max_mmap_size(av[1]); |
printf("max = %u\n", max); |
/* |
* Cycle through the given filename, in <max>-byte |
* segments. |
*/ |
while ((t = sum(av[1], off, max)) != -1) { |
s += t; |
off += max; |
} |
printf("sum = %qd\n", s); |
return 0; |
} |
Last updated: 2010-01-15