@@ -1,53 +1,103 @@
#pragma once
#include < exception>
#if defined(_WIN32)
# include < Windows.h>
#elif defined(__APPLE__)
# include < sys/mman.h>
#endif
#include < windows.h>
#include < optional>
#include " result.hpp"
#include " block.hpp"
struct win32_exception : std::exception
namespace cova ::memory::virtual_
{
DWORD const last_error;
explicit win32_exception () : last_error(GetLastError()) {}
};
result<block<>, uint32_t > allocate (size_t size);
result<block<>, uint32_t > allocate (void * first, size_t size);
result<void , uint32_t > 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<block<>, 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);
}
namespace cova ::mem::raw
{
struct virtual_alloc_exception : win32_exception {};
struct virtual_alloc_reserve_exception final : virtual_alloc_exception {};
struct virtual_alloc_commit_exception final : virtual_alloc_exception {};
inline result<block<>, 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<void , uint32_t > deallocate (block<> const & allocated)
{
if (!VirtualFree (allocated.address , 0 , MEM_RELEASE))
return uint32_t (GetLastError ());
return result<void , uint32_t >();
}
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 <bool >(VirtualFree (committed, 0 , MEM_DECOMMIT));
}
struct virtual_free_exception : win32_exception {};
struct virtual_alloc_decommit_exception final : virtual_free_exception {};
struct virtual_alloc_release_exception final : virtual_free_exception {};
inline bool release (void * const reserved)
{
return static_cast <bool >(VirtualFree (reserved, 0 , MEM_RELEASE));
}
#elif defined(__APPLE__)
// https://stackoverflow.com/questions/30057381/c-porting-virtualfree-in-os-x
void * reserve (size_t const size)
inline void * reserve (size_t const size)
{
auto const address = VirtualAlloc (nullptr , size, MEM_RESERVE, PAGE_NOACCESS); // don't use MEM_TOP_DOWN (https://randomascii.wordpress.com/2011/08/05/making-virtualalloc-arbitrarily-slower/)
if (address == nullptr )
throw virtual_alloc_reserve_exception ();
return address;
void * ptr = mmap (NULL , size, PROT_NONE, (MAP_PRIVATE | MAP_ANON), -1 , 0 );
msync (ptr, size, (MS_SYNC | MS_INVALIDATE));
}
void commit (void * const reserved, size_t const size)
inline void * commit (void * const reserved, size_t const size)
{
auto const result = VirtualAlloc (reserved, size, MEM_COMMIT, PAGE_READWRITE);
if (result == nullptr )
throw virtual_alloc_commit_exception ();
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 decommit (void * const committed)
inline bool decommit (void * const committed)
{
auto const result = VirtualFree (committed, 0 , MEM_DECOMMIT);
if (result == 0 )
throw virtual_alloc_decommit_exception ();
mmap (addr, size, PROT_NONE, MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1 , 0 );
msync (addr, size, MS_SYNC|MS_INVALIDATE);
}
void release (void * const reserved)
inline bool release (void * const reserved)
{
auto const result = VirtualFree (reserved, 0 , MEM_RELEASE);
if (result == 0 )
throw virtual_alloc_release_exception ();
msync (addr, size, MS_SYNC);
munmap (addr, size);
}
#endif
/*
@@ -80,4 +130,4 @@ namespace cova::mem::raw
}
*/
}
}