I would like to resize a memory mapped file on windows, without invalidating the pointer retrieved from a previous call to MapViewOfFileEx
. This way, all pointers to any file data that are stored throughout the application are not invalidated by the resize operation.
I found a solution for the problem but im not sure whether this approach is actually guaranteed to work in all cases.
This is my approach:
I reserve a large memory region with VirtualAlloc
:
reserved_pages_ptr = (char*)VirtualAlloc(nullptr, MAX_FILE_SIZE, MEM_RESERVE, PAGE_NOACCESS);
base_address = reserved_pages_ptr;
Every time the memory map is resized, I close the old file mapping, release the reserved pages and reserve the rest pages, that are not needed for the current size of the file:
filemapping_handle = CreateFileMappingW(...);
SYSTEM_INFO info;
GetSystemInfo(&info);
const DWORD page_size = info.dwAllocationGranularity;
const DWORD pages_needed = file_size / page_size + size_t(file_size % page_size != 0);
// release reserved pages:
VirtualFree(reserved_pages_ptr, 0, MEM_RELEASE);
// reserve rest pages:
reserved_pages_ptr = (char*)VirtualAlloc(
base_address + pages_needed * page_size,
MAX_FILE_SIZE - pages_needed * page_size,
MEM_RESERVE, PAGE_NOACCESS
);
if(reserved_pages_ptr != base_address + pages_needed * page_size)
{
//I hope this never happens...
}
Then i can map the view with MapViewOfFileEx
:
data_ = (char*)MapViewOfFileEx(filemapping_handle, ... , base_address);
if (data_ != base_address)
{
//I hope this also never happens...
}
Is this approach stable enough to guarantee, that the potential problems never occur? Do I need any synchronization to avoid problems with multithreading?
EDIT: I know that the most stable approach would be to change the rest of the application to allow invalidating all the file data pointers, but this solution could be an easy approach that mirrors the behavior of mmap
on Linux.