phobos/std/experimental/allocator/mmap_allocator.d
2015-10-02 07:35:09 -04:00

104 lines
3 KiB
D

module std.experimental.allocator.mmap_allocator;
// MmapAllocator
/**
Allocator (currently defined only for Posix) using $(D $(LUCKY mmap)) and $(D
$(LUCKY munmap)) directly. There is no additional structure: each call to $(D
allocate(s)) issues a call to $(D mmap(null, s, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)), and each call to $(D deallocate(b)) issues
$(D munmap(b.ptr, b.length)). So $(D MmapAllocator) is usually intended for
allocating large chunks to be managed by fine-granular allocators.
*/
struct MmapAllocator
{
/// The one shared instance.
static shared 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.
void[] allocate(size_t bytes) shared
{
import core.sys.posix.sys.mman;
if (!bytes) return null;
version(OSX) import core.sys.osx.sys.mman : MAP_ANON;
else version(linux) import core.sys.linux.sys.mman : MAP_ANON;
else version(FreeBSD) import core.sys.freebsd.sys.mman : MAP_ANON;
else static assert(false, "Add import for MAP_ANON here.");
auto p = mmap(null, bytes, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0);
if (p is MAP_FAILED) return null;
return p[0 .. bytes];
}
/// Ditto
bool deallocate(void[] b) shared
{
import core.sys.posix.sys.mman : munmap;
if (b.ptr) munmap(b.ptr, b.length) == 0 || assert(0);
return true;
}
}
else version(Windows)
{
import core.sys.windows.windows;
// kept to close the mapped memory.
private static shared(HANDLE) f;
/// Allocator API.
void[] allocate(size_t bytes) shared
{
if (!bytes) return null;
uint hiSz, loSz;
static if (bytes.sizeof == 8)
{
loSz = LOWORD(bytes);
hiSz = HIWORD(bytes);
}
else loSz = bytes;
auto fh = CreateFileMappingA(INVALID_HANDLE_VALUE,
LPSECURITY_ATTRIBUTES.init, PAGE_READWRITE, hiSz, loSz, null);
if (fh == INVALID_HANDLE_VALUE) return null;
auto p = MapViewOfFile(fh, FILE_MAP_ALL_ACCESS, 0u, 0u, bytes);
if (p == null)
{
CloseHandle(fh);
return null;
}
f = cast(typeof(f)) fh;
return p[0 .. bytes];
}
/// Ditto
bool deallocate(void[] b) shared
{
int result = true;
if (b.ptr)
result &= UnmapViewOfFile(b.ptr);
if (f != INVALID_HANDLE_VALUE)
result &= CloseHandle(cast(HANDLE) f);
return result != 0;
}
}
}
unittest
{
alias alloc = MmapAllocator.instance;
auto p = alloc.allocate(100);
assert(p.length == 100);
alloc.deallocate(p);
}