forked from 0ad/0ad
janwas
4be0fe18a0
. major compat fixes for interoperation with wxw. . add crashlog_sender (modified version of debgrpt wxw sample). compiles but untested, will be changed heavily further improvements: . wposix no longer declares CRT functions. instead, use CRT headers.. but don't allow their (incorrect/non-POSIX) declarations to propagate to users. . split up win.cpp into wstartup, wutil, winit . extern "C" -> EXTERN_C . move sdl.* to lib/external_libraries and add png.h+zlib.h (fixes for and include of the library) This was SVN commit r5028.
209 lines
6.4 KiB
C++
209 lines
6.4 KiB
C++
#include "precompiled.h"
|
|
#include "wmman.h"
|
|
|
|
#include "wposix_internal.h"
|
|
#include "crt_posix.h" // _get_osfhandle
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// memory mapping
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// convert POSIX PROT_* flags to their Win32 PAGE_* enumeration equivalents.
|
|
// used by mprotect.
|
|
static DWORD win32_prot(int prot)
|
|
{
|
|
// this covers all 8 combinations of read|write|exec
|
|
// (note that "none" means all flags are 0).
|
|
switch(prot & (PROT_READ|PROT_WRITE|PROT_EXEC))
|
|
{
|
|
case PROT_NONE:
|
|
return PAGE_NOACCESS;
|
|
case PROT_READ:
|
|
return PAGE_READONLY;
|
|
case PROT_WRITE:
|
|
// not supported by Win32; POSIX allows us to also grant read access.
|
|
return PAGE_READWRITE;
|
|
case PROT_EXEC:
|
|
return PAGE_EXECUTE;
|
|
case PROT_READ|PROT_WRITE:
|
|
return PAGE_READWRITE;
|
|
case PROT_READ|PROT_EXEC:
|
|
return PAGE_EXECUTE_READ;
|
|
case PROT_WRITE|PROT_EXEC:
|
|
// not supported by Win32; POSIX allows us to also grant read access.
|
|
return PAGE_EXECUTE_READWRITE;
|
|
case PROT_READ|PROT_WRITE|PROT_EXEC:
|
|
return PAGE_EXECUTE_READWRITE;
|
|
NODEFAULT;
|
|
}
|
|
}
|
|
|
|
|
|
int mprotect(void* addr, size_t len, int prot)
|
|
{
|
|
const DWORD flNewProtect = win32_prot(prot);
|
|
DWORD flOldProtect; // required by VirtualProtect
|
|
BOOL ok = VirtualProtect(addr, len, flNewProtect, &flOldProtect);
|
|
WARN_RETURN_IF_FALSE(ok);
|
|
return 0;
|
|
}
|
|
|
|
|
|
// called when flags & MAP_ANONYMOUS
|
|
static LibError mmap_mem(void* start, size_t len, int prot, int flags, int fd, void** pp)
|
|
{
|
|
// sanity checks. we don't care about these but enforce them to
|
|
// ensure callers are compatible with mmap.
|
|
// .. MAP_ANONYMOUS is documented to require this.
|
|
debug_assert(fd == -1);
|
|
// .. if MAP_SHARED, writes are to change "the underlying [mapped]
|
|
// object", but there is none here (we're backed by the page file).
|
|
debug_assert(flags & MAP_PRIVATE);
|
|
|
|
// see explanation at MAP_NORESERVE definition.
|
|
bool want_commit = (prot != PROT_NONE && !(flags & MAP_NORESERVE));
|
|
|
|
// decommit a given area (leaves its address space reserved)
|
|
if(!want_commit && start != 0 && flags & MAP_FIXED)
|
|
{
|
|
MEMORY_BASIC_INFORMATION mbi;
|
|
WARN_RETURN_IF_FALSE(VirtualQuery(start, &mbi, sizeof(mbi)));
|
|
if(mbi.State == MEM_COMMIT)
|
|
{
|
|
WARN_IF_FALSE(VirtualFree(start, len, MEM_DECOMMIT));
|
|
*pp = 0;
|
|
// make sure *pp won't be misinterpreted as an error
|
|
cassert(MAP_FAILED != 0);
|
|
return INFO::OK;
|
|
}
|
|
}
|
|
|
|
DWORD flAllocationType = want_commit? MEM_COMMIT : MEM_RESERVE;
|
|
DWORD flProtect = win32_prot(prot);
|
|
void* p = VirtualAlloc(start, len, flAllocationType, flProtect);
|
|
if(!p)
|
|
WARN_RETURN(ERR::NO_MEM);
|
|
*pp = p;
|
|
return INFO::OK;
|
|
}
|
|
|
|
|
|
// given mmap prot and flags, output protection/access values for use with
|
|
// CreateFileMapping / MapViewOfFile. they only support read-only,
|
|
// read/write and copy-on-write, so we dumb it down to that and later
|
|
// set the correct (and more restrictive) permission via mprotect.
|
|
static LibError mmap_file_access(int prot, int flags, DWORD& flProtect, DWORD& dwAccess)
|
|
{
|
|
// assume read-only; other cases handled below.
|
|
flProtect = PAGE_READONLY;
|
|
dwAccess = FILE_MAP_READ;
|
|
|
|
if(prot & PROT_WRITE)
|
|
{
|
|
// determine write behavior: (whether they change the underlying file)
|
|
switch(flags & (MAP_SHARED|MAP_PRIVATE))
|
|
{
|
|
// .. changes are written to file.
|
|
case MAP_SHARED:
|
|
flProtect = PAGE_READWRITE;
|
|
dwAccess = FILE_MAP_WRITE; // read and write
|
|
break;
|
|
// .. copy-on-write mapping; writes do not affect the file.
|
|
case MAP_PRIVATE:
|
|
flProtect = PAGE_WRITECOPY;
|
|
dwAccess = FILE_MAP_COPY;
|
|
break;
|
|
// .. either none or both of the flags are set. the latter is
|
|
// definitely illegal according to POSIX and some man pages
|
|
// say exactly one must be set, so abort.
|
|
default:
|
|
WARN_RETURN(ERR::INVALID_PARAM);
|
|
}
|
|
}
|
|
|
|
return INFO::OK;
|
|
}
|
|
|
|
|
|
static LibError mmap_file(void* start, size_t len, int prot, int flags,
|
|
int fd, off_t ofs, void** pp)
|
|
{
|
|
debug_assert(fd != -1); // handled by mmap_mem
|
|
|
|
WIN_SAVE_LAST_ERROR;
|
|
|
|
HANDLE hFile = HANDLE_from_intptr(_get_osfhandle(fd));
|
|
if(hFile == INVALID_HANDLE_VALUE)
|
|
WARN_RETURN(ERR::INVALID_PARAM);
|
|
|
|
// MapViewOfFileEx will fail if the "suggested" base address is
|
|
// nonzero but cannot be honored, so wipe out <start> unless MAP_FIXED.
|
|
if(!(flags & MAP_FIXED))
|
|
start = 0;
|
|
|
|
// choose protection and access rights for CreateFileMapping /
|
|
// MapViewOfFile. these are weaker than what PROT_* allows and
|
|
// are augmented below by subsequently mprotect-ing.
|
|
DWORD flProtect; DWORD dwAccess;
|
|
RETURN_ERR(mmap_file_access(prot, flags, flProtect, dwAccess));
|
|
|
|
// enough foreplay; now actually map.
|
|
const HANDLE hMap = CreateFileMapping(hFile, 0, flProtect, 0, 0, (LPCSTR)0);
|
|
// .. create failed; bail now to avoid overwriting the last error value.
|
|
if(!hMap)
|
|
WARN_RETURN(ERR::NO_MEM);
|
|
const DWORD ofs_hi = u64_hi(ofs), ofs_lo = u64_lo(ofs);
|
|
void* p = MapViewOfFileEx(hMap, dwAccess, ofs_hi, ofs_lo, (SIZE_T)len, start);
|
|
// .. make sure we got the requested address if MAP_FIXED was passed.
|
|
debug_assert(!(flags & MAP_FIXED) || (p == 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).
|
|
CloseHandle(hMap);
|
|
// .. map failed; bail now to avoid "restoring" the last error value.
|
|
if(!p)
|
|
WARN_RETURN(ERR::NO_MEM);
|
|
|
|
// slap on correct (more restrictive) permissions.
|
|
(void)mprotect(p, len, prot);
|
|
|
|
WIN_RESTORE_LAST_ERROR;
|
|
*pp = p;
|
|
return INFO::OK;
|
|
}
|
|
|
|
|
|
void* mmap(void* start, size_t len, int prot, int flags, int fd, off_t ofs)
|
|
{
|
|
void* p;
|
|
LibError err;
|
|
if(flags & MAP_ANONYMOUS)
|
|
err = mmap_mem(start, len, prot, flags, fd, &p);
|
|
else
|
|
err = mmap_file(start, len, prot, flags, fd, ofs, &p);
|
|
if(err < 0)
|
|
{
|
|
WARN_ERR(err);
|
|
LibError_set_errno(err);
|
|
return MAP_FAILED;
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
|
|
int munmap(void* start, size_t UNUSED(len))
|
|
{
|
|
// UnmapViewOfFile checks if start was returned by MapViewOfFile*;
|
|
// if not, it will fail.
|
|
BOOL ok = UnmapViewOfFile(start);
|
|
if(!ok)
|
|
// VirtualFree requires dwSize to be 0 (entire region is released).
|
|
ok = VirtualFree(start, 0, MEM_RELEASE);
|
|
|
|
WARN_RETURN_IF_FALSE(ok); // both failed
|
|
return 0;
|
|
}
|
|
|