I hope someone on this list is sufficiently familiar with file_mapping,
mapped_region and "Fixed Address Maping" to be able to offer advice.
I have a very large file, and I want to map pairs of system-page-sized
blocks from it into memory. The catch: I want to map non-consecutive
blocks from the file into consecutive memory addresses. For example,
with block 42 mapped to BASE_ADDRESS, I might want block 7 mapped to
BASE_ADDRESS+PAGE_SIZE.
Under Linux, using mmap() directly, I can use one of two approaches:
1. I can map two pages from the first file-block-start-location, then
map one block from the second, using MAP_FIXED, at the address returned
by the first mapping plus one page.
2. I could map two pages of /dev/zero - then map the first and second
pages explicitly using MAP_FIXED into that address space - this copes
with the case where the first block in memory is the last block of the
file, but has an overhead.
Both approaches seem to work, though I've not done extensive testing.
I'd prefer to avoid using mmap directly - both to gain the advantages of
a well-tested library using high-level C++ idioms - and to compile
cross-platform... definitely targeting Linux and Windows - but maybe
other platforms too.
When I attempt to use the above strategy, I get a
boost::interprocess_exception::library_error - though I'm not sure why.
The following code fails on both Linux and Windows:
--
size_t page_size=mapped_region::get_page_size();
file_mapping m("file.dat", read_write);
mapped_region ra(m,read_write,0,2*page_size);
uint8_t *base=reinterpret_cast(ra.get_address());
mapped_region rb(m,read_write,2*page_size,page_size,base+page_size); //FAILS
--
whereas, the following appeared to work under Windows 7 (but not Linux)
- perhaps by fluke of the way address space was allocated:
--
size_t page_size=mapped_region::get_page_size();
file_mapping m("file.dat", read_write);
mapped_region ra(m,read_write,0,page_size); // N.B. Map 1 page only
uint8_t *base=reinterpret_cast(ra.get_address());
mapped_region rb(m,read_write,2*page_size,page_size,base+page_size);
--
The documentation seems focused on MAP_FIXED being used to map specific
data in a file into the same memory address on every invocation - with
the obvious reference to validity of pointers referencing the mapped
address space. Pointers are not a problem for me - my file contains no
pointers - just a long stream of application-specific values. I only
need to explicitly control two pages to be mapped into contiguous memory
- I can be flexible about the mapped base address for the pair of pages
- and it doesn't matter if different addresses are chosen on successive
invocations.. as long as, in memory, the byte following the last byte of
the first page is the first byte of the second page for an arbitrary
pair of pages... irrespective of the locations of those pages in the file.
Is this a use case that boost::interprocess intends to support?
What is the most appropriate, robust, platform independent, way to
reserve address space in order map into fixed addresses to ensure
contiguous mappings?
Do I need to mmap /dev/zero for POSIX systems - and use VirtualAlloc
with MEM_RESERVE on Windows myself in order to use fixed-address memory
mapping of files? Does boost offer anything to make this platform
independent - or am I 'on my own'?