Boost logo

Boost Users :

Subject: [Boost-users] Interprocess file mapping - fixed addresses
From: Steve (sjh_boost_at_[hidden])
Date: 2012-05-13 11:41:06


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<uint8_t*>(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<uint8_t*>(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'?

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net