A simple mmap() readonly example
Problem:
You want to use mmap()
from sys/stat.h
POSIX header to map a file for reading (not writing). You can’t find any simple bare example on the internet.
Solution
If you’re only interest in a high-level wrapper, please have a look at this boost::iostreams mmap example and the boost::iostreams mmap reference. Keep in mind, however, boost::iostreams
does not provide all functionality mmap()
does and boost::iostreams
is quite a large dependency (you need to link the library!). However, it might be the best option for better portability to non-unix systems.
Here’s a minimal mmap()
based cat
implementation. It is not efficient, but demonstrates the important concepts. It uses the stat()
-based getFilesize()
function from this previous post
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <assert.h>
size_t getFilesize(const char* filename) {
struct stat st;
stat(filename, &st);
return st.st_size;
}
int main(int argc, char** argv) {
size_t filesize = getFilesize(argv[1]);
//Open file
int fd = open(argv[1], O_RDONLY, 0);
assert(fd != -1);
//Execute mmap
void* mmappedData = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE | MAP_POPULATE, fd, 0);
assert(mmappedData != MAP_FAILED);
//Write the mmapped data to stdout (= FD #1)
write(1, mmappedData, filesize);
//Cleanup
int rc = munmap(mmappedData, filesize);
assert(rc == 0);
close(fd);
}
Compile using
g++ -o mmap-example mmap-example.cpp
Run like this:
echo "hello mmap world" > test.txt
./mmap-example test.txt
Step-by-step discussion
Step 1: Get the filesize. You need to know that before calling mmap, but you can also mmap a subset only.
Step 2: Open the file. Keep in mind you can’t use the fopen() function directly (you could use fileno() on the FILE object) because you need the file descriptor! In this case we’re using O_RDONLY because we want to mmap() read-only.
Step 3: Call mmap() with those parameters:
- NULL: Let the kernel decide which address to mmap at. This is the recommended address parameter.
- filesize: The size of the file. For readonly-mmap only values <= the real filesize make sense.
PROT_READ
: Map the file read-only (in other words, use read-only page protection)MAP_PRIVATE
: Usually this means don’t write changes to the mmaped memory back to the file, but we mapped it readonly anyway, so using this or MAP_SHARED does’t make any noticeable difference.MAP_POPULATE
: Let the kernel preload parts of the file. This is a performance optimization. There is no absolute need to use this.- fd: The unix file descriptor to map (if you have a
FILE*
, you can get the descriptor number usingfileno()
). Must be opened * 0: The offset from the beginning of the file. 0 because we want to map the entire file
For a detailed mmap()
reference, see the Opengroup page on mmap
Error-checking
The above implementation does not properly check for errors because it’s only a minimal example.
In any case, you should at least check if the value returned by mmap()
is == MAP_FAILED
. See the Opengroup page on mmap for details.
Update 2013/09/26: Close the file descriptor in cleanup section
Update 2016/01/07: assert != MAP_FAILED
instead of NULL (Thanks to Erik Sjölund)