Sign in to follow this  

Cross platform file mapping library

This topic is 4856 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Is there some sort of library that has a simple API for memory mapping a file, and is also cross platform? I was working on a little project and needed to memory map some files. I was using wxWindows so it was intended to be able to compile out of the box for either platform using exactly the same code. I wrote a simple wrapper for the memory mapping functions on Linux and Windows and they seem to work okay. I looked at Freshmeat for something similar and didn't find anything. If there isn't already something already out there that does the same thing I may try to clean up the code and get it in library form, or at least post the code somewhere, maybe even write a simple article to go with it. Is it worth my time?

Share this post


Link to post
Share on other sites
Windows is the odd man out here, so what I did is implement mmap() for Win32. That way, if you want to add a layer on top (say to prevent leaks), you don't have to write 2 versions of it.

Code (licensed under the GPL):
//
// <sys/mman.h>
//

// mmap prot flags
#define PROT_NONE 0x00 // no access (not supported on Win32)
#define PROT_READ 0x01
#define PROT_WRITE 0x02

// mmap flags
#define MAP_SHARED 0x01 // share changes across processes
#define MAP_PRIVATE 0x02 // private copy-on-write mapping
#define MAP_FIXED 0x04

#define MAP_FAILED 0

extern void* mmap(void* start, size_t len, int prot, int flags, int fd, off_t offset);
extern int munmap(void* start, size_t len);



void* mmap(void* const user_start, const size_t len, const int prot, const int flags, const int fd, const off_t offset)
{
{
WIN_SAVE_LAST_ERROR;

// assume fd = -1 (requesting mapping backed by page file),
// so that we notice invalid file handles below.
HANDLE hFile = INVALID_HANDLE_VALUE;
if(fd != -1)
{
hFile = mk_handle(_get_osfhandle(fd));
if(hFile == INVALID_HANDLE_VALUE)
{
debug_warn("mmap: invalid file handle");
goto fail;
}
}

// MapView.. will choose start address unless MAP_FIXED was specified.
void* start = 0;
if(flags & MAP_FIXED)
{
start = user_start;
if(start == 0) // assert below would fire
goto fail;
}

// figure out access rights.
// note: reads are always allowed (Win32 limitation).

SECURITY_ATTRIBUTES sec = { sizeof(SECURITY_ATTRIBUTES), (void*)0, FALSE };
DWORD flProtect = PAGE_READONLY;
DWORD dwAccess = FILE_MAP_READ;

// .. no access: not possible on Win32.
if(prot == PROT_NONE)
goto fail;
// .. write or read/write (Win32 doesn't support write-only)
if(prot & PROT_WRITE)
{
flProtect = PAGE_READWRITE;

const bool shared = (flags & MAP_SHARED ) != 0;
const bool priv = (flags & MAP_PRIVATE) != 0;
// .. both aren't allowed
if(shared && priv)
goto fail;
// .. changes are shared & written to file
else if(shared)
{
sec.bInheritHandle = TRUE;
dwAccess = FILE_MAP_ALL_ACCESS;
}
// .. private copy-on-write mapping
else if(priv)
{
flProtect = PAGE_WRITECOPY;
dwAccess = FILE_MAP_COPY;
}
}

// now actually map.
const DWORD len_hi = (DWORD)((u64)len >> 32);
// careful! language doesn't allow shifting 32-bit types by 32 bits.
const DWORD len_lo = (DWORD)len & 0xffffffff;
const HANDLE hMap = CreateFileMapping(hFile, &sec, flProtect, len_hi, len_lo, (LPCSTR)0);
if(hMap == INVALID_HANDLE_VALUE)
// bail now so that MapView.. doesn't overwrite the last error value.
goto fail;
void* ptr = MapViewOfFileEx(hMap, dwAccess, len_hi, offset, len_lo, start);

// free the mapping object now, so that we don't have to hold on to its
// handle until munmap(). it's not actually released yet due to the
// reference held by MapViewOfFileEx (if it succeeded).
if(hMap != INVALID_HANDLE_VALUE) // avoid "invalid handle" error
CloseHandle(hMap);

if(!ptr)
// bail now, before the last error value is restored,
// but after freeing the mapping object.
goto fail;

assert(!(flags & MAP_FIXED) || (ptr == start));
// fixed => ptr = start

WIN_RESTORE_LAST_ERROR;

return ptr;
}
fail:
return MAP_FAILED;
}


int munmap(void* const start, const size_t len)
{
UNUSED(len);
BOOL ok = UnmapViewOfFile(start);
return ok? 0 : -1;
}


Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by Jan Wassenberg
Windows is the odd man out here, so what I did is implement mmap() for Win32. That way, if you want to add a layer on top (say to prevent leaks), you don't have to write 2 versions of it.

Code (licensed under the GPL):
*** Source Snippet Removed ***

Woah, nifty.

Where did this come from:
hFile = mk_handle(_get_osfhandle(fd));
Is that part of the Win32 API?

Share this post


Link to post
Share on other sites
mk_handle (now christened cast_to_HANDLE, for less confusion :)) just does a type cast (my compiler is quite picky about converting to/from HANDLE).
// cast intptr_t to HANDLE; centralized for easier changing, e.g. avoiding
// warnings. i = -1 converts to INVALID_HANDLE_VALUE (same value).
static inline HANDLE cast_to_HANDLE(intptr_t i)
{
return (HANDLE)((char*)0 + i);
}


The real work is in _get_osfhandle (a semi-internal CRT function) - it gives us the HANDLE returned by CreateFile when the file was opened. Discovering that routine made the mmap wrapper feasible :)

Share this post


Link to post
Share on other sites

This topic is 4856 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this