Skip to content

Instantly share code, notes, and snippets.

@TronicLabs
Forked from NickStrupat/virtual_memory.hpp
Created June 12, 2024 05:19
Show Gist options
  • Save TronicLabs/fb873b4baf6fb54cc2ebaf40f6071cc6 to your computer and use it in GitHub Desktop.
Save TronicLabs/fb873b4baf6fb54cc2ebaf40f6071cc6 to your computer and use it in GitHub Desktop.

Revisions

  1. @NickStrupat NickStrupat revised this gist Jun 16, 2021. 1 changed file with 23 additions and 3 deletions.
    26 changes: 23 additions & 3 deletions virtual_memory.hpp
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@

    #if defined(_WIN32)
    # include <Windows.h>
    #elif defined(__APPLE__)
    #elif defined(__APPLE__) || defined(LINUX)
    # include <sys/mman.h>
    #endif

    @@ -88,15 +88,35 @@ namespace cova::memory::virtual_

    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);
    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

    /*
  2. @NickStrupat NickStrupat revised this gist Jun 11, 2021. 1 changed file with 82 additions and 32 deletions.
    114 changes: 82 additions & 32 deletions virtual_memory.hpp
    Original file line number Diff line number Diff line change
    @@ -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
    }
    */
    }
    }
  3. @NickStrupat NickStrupat created this gist Feb 3, 2019.
    83 changes: 83 additions & 0 deletions virtual_memory.hpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,83 @@
    #pragma once

    #include <exception>

    #include <windows.h>

    struct win32_exception : std::exception
    {
    DWORD const last_error;
    explicit win32_exception() : last_error(GetLastError()) {}
    };

    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 {};

    struct virtual_free_exception : win32_exception {};
    struct virtual_alloc_decommit_exception final : virtual_free_exception {};
    struct virtual_alloc_release_exception final : virtual_free_exception {};

    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 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 decommit(void * const committed)
    {
    auto const result = VirtualFree(committed, 0, MEM_DECOMMIT);
    if (result == 0)
    throw virtual_alloc_decommit_exception();
    }

    void release(void * const reserved)
    {
    auto const result = VirtualFree(reserved, 0, MEM_RELEASE);
    if (result == 0)
    throw virtual_alloc_release_exception();
    }

    /*
    //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);
    }
    */
    }