#pragma once #if defined(_WIN32) # include #elif defined(__APPLE__) || defined(LINUX) # include #endif #include #include "result.hpp" #include "block.hpp" namespace cova::memory::virtual_ { result, uint32_t> allocate(size_t size); result, uint32_t> allocate(void * first, size_t size); result deallocate(block<> const & allocated); void * reserve(size_t size); void * reserve(void * location, size_t size); void * commit(void * reserved, size_t size); bool decommit(void * committed); bool release(void * reserved); #if defined(_WIN32) inline result, uint32_t> allocate(size_t const size) { auto const p = VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (p == nullptr) return uint32_t(GetLastError()); return block<>(p, size); } inline result, uint32_t> allocate(void * const first, size_t const size) { auto const p = VirtualAlloc(first, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (p == nullptr) return uint32_t(GetLastError()); if (p != first) return uint32_t(-1); return block<>(p, size); } inline result deallocate(block<> const & allocated) { if (!VirtualFree(allocated.address, 0, MEM_RELEASE)) return uint32_t(GetLastError()); return result(); } inline void * reserve(size_t const size) { return VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_NOACCESS); // don't use MEM_TOP_DOWN (https://randomascii.wordpress.com/2011/08/05/making-virtualalloc-arbitrarily-slower/) } inline void * commit(void * const reserved, size_t const size) { return VirtualAlloc(reserved, size, MEM_COMMIT, PAGE_READWRITE); } inline bool decommit(void * const committed) { return static_cast(VirtualFree(committed, 0, MEM_DECOMMIT)); } inline bool release(void * const reserved) { return static_cast(VirtualFree(reserved, 0, MEM_RELEASE)); } #elif defined(__APPLE__) // https://stackoverflow.com/questions/30057381/c-porting-virtualfree-in-os-x inline void * reserve(size_t const size) { void * ptr = mmap(NULL, size, PROT_NONE, (MAP_PRIVATE | MAP_ANON), -1, 0); msync(ptr, size, (MS_SYNC | MS_INVALIDATE)); } inline void * commit(void * const reserved, size_t const size) { void * ptr = mmap(addr, size, (PROT_READ | PROT_WRITE), (MAP_FIXED | MAP_SHARED | MAP_ANON), -1, 0); msync(addr, size, (MS_SYNC | MS_INVALIDATE)); } inline bool decommit(void * const committed) { mmap(addr, size, PROT_NONE, (MAP_FIXED | MAP_PRIVATE | MAP_ANON), -1, 0); msync(addr, size, MS_SYNC | MS_INVALIDATE); } inline bool release(void * const reserved) { msync(addr, size, MS_SYNC); munmap(addr, size); } #elif defined(LINUX) inline void * reserve(size_t const size) { void * ptr = mmap(NULL, size, PROT_NONE, (MAP_PRIVATE | MAP_ANONYMOUS), -1, 0); } inline void * commit(void * const reserved, size_t const size) { void * ptr = mmap(addr, size, (PROT_READ | PROT_WRITE), (MAP_FIXED | MAP_SHARED | MAP_ANONYMOUS), -1, 0); } inline bool decommit(void * const committed) { mmap(addr, size, PROT_NONE, (MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS), -1, 0); } inline bool release(void * const reserved) { munmap(addr, size); } #endif /* //https://stackoverflow.com/questions/30057381/c-porting-virtualfree-in-os-x //to reserve virtual address space //equivalent of VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS) void* ptr = mmap(NULL, size, PROT_NONE, (MAP_PRIVATE | MAP_ANON), -1, 0); msync(ptr, size, (MS_SYNC | MS_INVALIDATE)); //to free ALL virtual address space //equivalent of VirtualFree(addr, 0, MEM_RELEASE) //where "size" is the size of the entire virtual address space and "addr" the starting address msync(addr, size, MS_SYNC); munmap(addr, size); //to allocate physical memory //equivalent of VirtualAlloc(addr, size, MEM_COMMIT, PAGE_READWRITE) void* ptr = mmap(addr, size, (PROT_READ | PROT_WRITE), (MAP_FIXED | MAP_SHARED | MAP_ANON), -1, 0); msync(addr, size, (MS_SYNC | MS_INVALIDATE)); void DecommitMemory(void* addr, size_t size) { // instead of unmapping the address, we're just gonna trick // the TLB to mark this as a new mapped area which, due to // demand paging, will not be committed until used. mmap(addr, size, PROT_NONE, MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0); msync(addr, size, MS_SYNC|MS_INVALIDATE); } */ }