#include <folly/portability/SysMman.h>
#ifdef _WIN32
#include <cassert>
#include <folly/Portability.h>
#include <folly/portability/Windows.h>
static bool mmap_to_page_protection(int prot, DWORD& ret, DWORD& acc) {
if (prot == PROT_NONE) {
ret = PAGE_NOACCESS;
acc = 0;
} else if (prot == PROT_READ) {
ret = PAGE_READONLY;
acc = FILE_MAP_READ;
} else if (prot == PROT_EXEC) {
ret = PAGE_EXECUTE;
acc = FILE_MAP_EXECUTE;
} else if (prot == (PROT_READ | PROT_EXEC)) {
ret = PAGE_EXECUTE_READ;
acc = FILE_MAP_READ | FILE_MAP_EXECUTE;
} else if (prot == (PROT_READ | PROT_WRITE)) {
ret = PAGE_READWRITE;
acc = FILE_MAP_READ | FILE_MAP_WRITE;
} else if (prot == (PROT_READ | PROT_WRITE | PROT_EXEC)) {
ret = PAGE_EXECUTE_READWRITE;
acc = FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_EXECUTE;
} else {
return false;
}
return true;
}
static size_t alignToAllocationGranularity(size_t s) {
static size_t granularity = [] {
static SYSTEM_INFO inf;
GetSystemInfo(&inf);
return inf.dwAllocationGranularity;
}();
return (s + granularity - 1) / granularity * granularity;
}
extern "C" {
int madvise(const void* , size_t , int ) {
return 0;
}
int mlock(const void* addr, size_t len) {
if (addr == nullptr && len == 0) {
return 0;
}
if (!VirtualLock((void*)addr, len)) {
return -1;
}
return 0;
}
namespace {
constexpr uint32_t kMMapLengthMagic = 0xFACEB00C;
struct MemMapDebugTrailer {
size_t length;
uint32_t magic;
};
void* mmapWinArgs(
void* addr,
size_t length,
int prot,
int flags,
int fd,
DWORD offHigh,
DWORD offLow) {
if ((flags & (MAP_ANONYMOUS | MAP_SHARED)) == (MAP_ANONYMOUS | MAP_SHARED)) {
return MAP_FAILED;
}
if ((flags & MAP_PRIVATE) == MAP_PRIVATE &&
(prot & PROT_WRITE) == PROT_WRITE && fd != -1) {
return MAP_FAILED;
}
if (!(flags & MAP_ANONYMOUS) && fd == -1) {
return MAP_FAILED;
}
DWORD newProt;
DWORD accessFlags;
if (!mmap_to_page_protection(prot, newProt, accessFlags)) {
return MAP_FAILED;
}
void* ret;
if (!(flags & MAP_ANONYMOUS) || (flags & MAP_SHARED)) {
HANDLE h = INVALID_HANDLE_VALUE;
if (!(flags & MAP_ANONYMOUS)) {
h = (HANDLE)_get_osfhandle(fd);
}
HANDLE fmh = CreateFileMapping(
h,
nullptr,
newProt,
(DWORD)((length >> 32) & 0xFFFFFFFF),
(DWORD)(length & 0xFFFFFFFF),
nullptr);
if (fmh == nullptr) {
return MAP_FAILED;
}
ret = MapViewOfFileEx(fmh, accessFlags, offHigh, offLow, 0, addr);
if (ret == nullptr) {
ret = MAP_FAILED;
}
CloseHandle(fmh);
} else {
auto baseLength = length;
if (folly::kIsDebug) {
length += sizeof(MemMapDebugTrailer);
}
length = alignToAllocationGranularity(length);
ret = VirtualAlloc(addr, length, MEM_COMMIT | MEM_RESERVE, newProt);
if (ret == nullptr) {
return MAP_FAILED;
}
if (folly::kIsDebug) {
auto deb = (MemMapDebugTrailer*)((char*)ret + baseLength);
deb->length = baseLength;
deb->magic = kMMapLengthMagic;
}
}
return ret;
}
}
void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t off) {
return mmapWinArgs(
addr, length, prot, flags, fd, (DWORD)(0), (DWORD)(off & 0xFFFFFFFF));
}
void* mmap64(
void* addr, size_t length, int prot, int flags, int fd, off64_t off) {
return mmapWinArgs(
addr,
length,
prot,
flags,
fd,
(DWORD)(off >> 32) & 0xFFFFFFFF,
(DWORD)(off & 0xFFFFFFFF));
}
int mprotect(void* addr, size_t size, int prot) {
DWORD newProt;
DWORD access;
if (!mmap_to_page_protection(prot, newProt, access)) {
return -1;
}
DWORD oldProt;
BOOL res = VirtualProtect(addr, size, newProt, &oldProt);
if (!res) {
return -1;
}
return 0;
}
int munlock(const void* addr, size_t length) {
if (addr == nullptr && length == 0) {
return 0;
}
if (!VirtualUnlock((void*)addr, length)) {
return -1;
}
return 0;
}
int munmap(void* addr, size_t length) {
if (!UnmapViewOfFile(addr)) {
if (folly::kIsDebug) {
MEMORY_BASIC_INFORMATION inf;
VirtualQuery(addr, &inf, sizeof(inf));
assert(inf.AllocationBase == addr);
auto deb = (MemMapDebugTrailer*)((char*)addr + length);
assert(deb->length == length);
assert(deb->magic == kMMapLengthMagic);
}
if (!VirtualFree(addr, 0, MEM_RELEASE)) {
return -1;
}
return 0;
}
return 0;
}
}
#endif