Mac OS X Reference Library Apple Developer
Search

Simulating a 64-Bit Address Space with mmap and munmap

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

Did this document help you? Yes It's good, but... Not helpful...