// Written in the D programming language./**Source: $(PHOBOSSRC std/experimental/allocator/_mmap_allocator.d)*/module std.experimental.allocator.mmap_allocator;/**Allocator (currently defined only for Posix and Windows) using$(D $(LINK2 https://en.wikipedia.org/wiki/Mmap, mmap))and $(D $(LUCKY munmap)) directly (or their Windows equivalents). There is noadditional structure: each call to `allocate(s)` issues a call to$(D mmap(null, s, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)),and each call to `deallocate(b)` issues $(D munmap(b.ptr, b.length)).So `MmapAllocator` is usually intended for allocating large chunks to bemanaged by fine-granular allocators.*/struct MmapAllocator{ /// The one shared instance. static shared const MmapAllocator instance; /** Alignment is page-size and hardcoded to 4096 (even though on certain systems it could be larger). */ enum size_t alignment = 4096; version (Posix) { /// Allocator API. pure nothrow @nogc @safe void[] allocate(size_t bytes) shared const { import core.sys.posix.sys.mman : MAP_ANON, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_FAILED; if (!bytes) return null; const errnosave = (() @trusted => fakePureErrno())(); // For purity revert changes to errno. auto p = (() @trusted => fakePureMmap(null, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0))(); if (p is MAP_FAILED) { (() @trusted => fakePureErrno() = errnosave)(); // errno only changed on MAP_FAILED. return null; } return (() @trusted => p[0 .. bytes])(); } /// Ditto pure nothrow @nogc bool deallocate(void[] b) shared const { // Because we assert(0) on error we don't need to reset errno for purity. if (b.ptr) fakePureMunmap(b.ptr, b.length) == 0 || assert(0); return true; } // Anonymous mmap might be zero-filled on all Posix systems but // not all commit to this in the documentation. version (linux) // http://man7.org/linux/man-pages/man2/mmap.2.html package alias allocateZeroed = allocate; else version (NetBSD) // https://man.netbsd.org/mmap.2 package alias allocateZeroed = allocate; else version (Solaris) // https://docs.oracle.com/cd/E88353_01/html/E37841/mmap-2.html package alias allocateZeroed = allocate; else version (AIX) // https://www.ibm.com/support/knowledgecenter/en/ssw_aix_71/com.ibm.aix.basetrf1/mmap.htm package alias allocateZeroed = allocate; } else version (Windows) { import core.sys.windows.winnt : MEM_COMMIT, PAGE_READWRITE, MEM_RELEASE; /// Allocator API. pure nothrow @nogc @safe void[] allocate(size_t bytes) shared const { if (!bytes) return null; // For purity ensure last-error does not visibly change. const lastErrorSave = (() @trusted => GetLastError())(); auto p = (() @trusted => VirtualAlloc(null, bytes, MEM_COMMIT, PAGE_READWRITE))(); if (p == null) { // Last-error only changed if allocation failed. (() @trusted => SetLastError(lastErrorSave))(); return null; } return (() @trusted => p[0 .. bytes])(); } /// Ditto pure nothrow @nogc bool deallocate(void[] b) shared const { const lastErrorSave = GetLastError(); // For purity ensure last-error does not visibly change. scope(exit) SetLastError(lastErrorSave); return b.ptr is null || VirtualFree(b.ptr, 0, MEM_RELEASE) != 0; } package alias allocateZeroed = allocate; }}// pure wrappers around `mmap` and `munmap` because they are used here locally// solely to perform allocation and deallocation which in this case is `pure`version (Posix)extern (C) private pure @system @nogc nothrow{ import core.sys.posix.sys.types : off_t; pragma(mangle, "fakePureErrnoImpl") ref int fakePureErrno(); pragma(mangle, "mmap") void* fakePureMmap(void*, size_t, int, int, int, off_t); pragma(mangle, "munmap") int fakePureMunmap(void*, size_t);}// Pure wrappers around VirtualAlloc/VirtualFree for use here only. Their use is sound// because when we call them we ensure that last-error is not visibly changed.version (Windows)extern (Windows) private pure @system @nogc nothrow{ import core.sys.windows.basetsd : SIZE_T; import core.sys.windows.windef : BOOL, DWORD; import core.sys.windows.winnt : LPVOID, PVOID; DWORD GetLastError(); void SetLastError(DWORD); PVOID VirtualAlloc(PVOID, SIZE_T, DWORD, DWORD); BOOL VirtualFree(PVOID, SIZE_T, DWORD);}pure nothrow @safe @nogc unittest{ alias alloc = MmapAllocator.instance; auto p = alloc.allocate(100); assert(p.length == 100); () @trusted { alloc.deallocate(p); p = null; }();}
// Written in the D programming language.
/**
Source: $(PHOBOSSRC std/experimental/allocator/_mmap_allocator.d)
*/
module std.experimental.allocator.mmap_allocator;
/**
Allocator (currently defined only for Posix and Windows) using
$(D $(LINK2 https://en.wikipedia.org/wiki/Mmap, mmap))
and $(D $(LUCKY munmap)) directly (or their Windows equivalents). There is no
additional structure: each call to `allocate(s)` issues a call to
$(D mmap(null, s, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)),
and each call to `deallocate(b)` issues $(D munmap(b.ptr, b.length)).
So `MmapAllocator` is usually intended for allocating large chunks to be
managed by fine-granular allocators.
*/
struct MmapAllocator
{
/// The one shared instance.
static shared const MmapAllocator instance;
/**
Alignment is page-size and hardcoded to 4096 (even though on certain systems
it could be larger).
*/
enum size_t alignment = 4096;
version (Posix)
{
/// Allocator API.
pure nothrow @nogc @safe
void[] allocate(size_t bytes) shared const
{
import core.sys.posix.sys.mman : MAP_ANON, PROT_READ,
PROT_WRITE, MAP_PRIVATE, MAP_FAILED;
if (!bytes) return null;
const errnosave = (() @trusted => fakePureErrno())(); // For purity revert changes to errno.
auto p = (() @trusted => fakePureMmap(null, bytes, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0))();
if (p is MAP_FAILED)
{
(() @trusted => fakePureErrno() = errnosave)(); // errno only changed on MAP_FAILED.
return null;
}
return (() @trusted => p[0 .. bytes])();
}
/// Ditto
pure nothrow @nogc
bool deallocate(void[] b) shared const
{
// Because we assert(0) on error we don't need to reset errno for purity.
if (b.ptr) fakePureMunmap(b.ptr, b.length) == 0 || assert(0);
return true;
}
// Anonymous mmap might be zero-filled on all Posix systems but
// not all commit to this in the documentation.
version (linux)
// http://man7.org/linux/man-pages/man2/mmap.2.html
package alias allocateZeroed = allocate;
else version (NetBSD)
// https://man.netbsd.org/mmap.2
package alias allocateZeroed = allocate;
else version (Solaris)
// https://docs.oracle.com/cd/E88353_01/html/E37841/mmap-2.html
package alias allocateZeroed = allocate;
else version (AIX)
// https://www.ibm.com/support/knowledgecenter/en/ssw_aix_71/com.ibm.aix.basetrf1/mmap.htm
package alias allocateZeroed = allocate;
}
else version (Windows)
{
import core.sys.windows.winnt : MEM_COMMIT, PAGE_READWRITE, MEM_RELEASE;
/// Allocator API.
pure nothrow @nogc @safe
void[] allocate(size_t bytes) shared const
{
if (!bytes) return null;
// For purity ensure last-error does not visibly change.
const lastErrorSave = (() @trusted => GetLastError())();
auto p = (() @trusted => VirtualAlloc(null, bytes, MEM_COMMIT, PAGE_READWRITE))();
if (p == null)
{
// Last-error only changed if allocation failed.
(() @trusted => SetLastError(lastErrorSave))();
return null;
}
return (() @trusted => p[0 .. bytes])();
}
/// Ditto
pure nothrow @nogc
bool deallocate(void[] b) shared const
{
const lastErrorSave = GetLastError(); // For purity ensure last-error does not visibly change.
scope(exit) SetLastError(lastErrorSave);
return b.ptr is null || VirtualFree(b.ptr, 0, MEM_RELEASE) != 0;
}
package alias allocateZeroed = allocate;
}
}
// pure wrappers around `mmap` and `munmap` because they are used here locally
// solely to perform allocation and deallocation which in this case is `pure`
version (Posix)
extern (C) private pure @system @nogc nothrow
{
import core.sys.posix.sys.types : off_t;
pragma(mangle, "fakePureErrnoImpl") ref int fakePureErrno();
pragma(mangle, "mmap") void* fakePureMmap(void*, size_t, int, int, int, off_t);
pragma(mangle, "munmap") int fakePureMunmap(void*, size_t);
}
// Pure wrappers around VirtualAlloc/VirtualFree for use here only. Their use is sound
// because when we call them we ensure that last-error is not visibly changed.
version (Windows)
extern (Windows) private pure @system @nogc nothrow
{
import core.sys.windows.basetsd : SIZE_T;
import core.sys.windows.windef : BOOL, DWORD;
import core.sys.windows.winnt : LPVOID, PVOID;
DWORD GetLastError();
void SetLastError(DWORD);
PVOID VirtualAlloc(PVOID, SIZE_T, DWORD, DWORD);
BOOL VirtualFree(PVOID, SIZE_T, DWORD);
}
pure nothrow @safe @nogc unittest
{
alias alloc = MmapAllocator.instance;
auto p = alloc.allocate(100);
assert(p.length == 100);
() @trusted { alloc.deallocate(p); p = null; }();
}