Make MmapPool allocations pure

This commit is contained in:
Eugen Wissner 2017-07-12 09:30:07 +02:00
parent fc53779d3f
commit 2bd612fd19

View File

@ -18,14 +18,61 @@ import tanya.memory.allocator;
version (Posix) version (Posix)
{ {
import core.stdc.errno;
import core.sys.posix.sys.mman;
import core.sys.posix.unistd; import core.sys.posix.unistd;
extern (C)
private void* mmap(void* addr,
size_t len,
int prot,
int flags,
int fd,
off_t offset) pure nothrow @system @nogc;
extern (C)
private int munmap(void* addr, size_t len) pure nothrow @system @nogc;
private void* mapMemory(const size_t len) pure nothrow @system @nogc
{
void* p = mmap(null,
len,
0x01 | 0x02, // PROT_READ | PROT_WRITE
0x0002 | 0x1000, // MAP_PRIVATE | MAP_ANON
-1,
0);
return p is (cast(void*) -1) ? null : p;
}
private bool unmapMemory(shared void* addr, const size_t len)
pure nothrow @system @nogc
{
return munmap(cast(void*) addr, len) == 0;
}
} }
else version (Windows) else version (Windows)
{ {
import core.sys.windows.winbase; import core.sys.windows.winbase : GetSystemInfo, SYSTEM_INFO;
import core.sys.windows.windows;
extern (Windows)
private void* VirtualAlloc(void*, size_t, uint, uint)
pure nothrow @system @nogc;
extern (Windows)
private int VirtualFree(void* addr, size_t len, uint)
pure nothrow @system @nogc;
private void* mapMemory(const size_t len) pure nothrow @system @nogc
{
return VirtualAlloc(null,
len,
0x00001000, // MEM_COMMIT
0x04); // PAGE_READWRITE
}
private bool unmapMemory(shared void* addr, const size_t len)
pure nothrow @system @nogc
{
return VirtualFree(cast(void*) addr, 0, 0x8000) == 0;
}
} }
/** /**
@ -78,7 +125,7 @@ final class MmapPool : Allocator
* *
* Returns: Pointer to the new allocated memory. * Returns: Pointer to the new allocated memory.
*/ */
void[] allocate(const size_t size) shared nothrow @nogc void[] allocate(const size_t size) shared pure nothrow @nogc
{ {
if (size == 0) if (size == 0)
{ {
@ -137,7 +184,7 @@ final class MmapPool : Allocator
* *
* Returns: Data the block points to or $(D_KEYWORD null). * Returns: Data the block points to or $(D_KEYWORD null).
*/ */
private void* findBlock(const ref size_t size) shared nothrow @nogc private void* findBlock(const ref size_t size) shared pure nothrow @nogc
{ {
Block block1; Block block1;
RegionLoop: for (auto r = head; r !is null; r = r.next) RegionLoop: for (auto r = head; r !is null; r = r.next)
@ -197,7 +244,7 @@ final class MmapPool : Allocator
* *
* Returns: Whether the deallocation was successful. * Returns: Whether the deallocation was successful.
*/ */
bool deallocate(void[] p) shared nothrow @nogc bool deallocate(void[] p) shared pure nothrow @nogc
{ {
if (p.ptr is null) if (p.ptr is null)
{ {
@ -219,14 +266,7 @@ final class MmapPool : Allocator
{ {
block.region.next.prev = block.region.prev; block.region.next.prev = block.region.prev;
} }
version (Posix) return unmapMemory(block.region, block.region.size);
{
return munmap(cast(void*) block.region, block.region.size) == 0;
}
version (Windows)
{
return VirtualFree(cast(void*) block.region, 0, MEM_RELEASE) == 0;
}
} }
// Merge blocks if neigbours are free. // Merge blocks if neigbours are free.
if (block.next !is null && block.next.free) if (block.next !is null && block.next.free)
@ -271,7 +311,7 @@ final class MmapPool : Allocator
* Returns: $(D_KEYWORD true) if successful, $(D_KEYWORD false) otherwise. * Returns: $(D_KEYWORD true) if successful, $(D_KEYWORD false) otherwise.
*/ */
bool reallocateInPlace(ref void[] p, const size_t size) bool reallocateInPlace(ref void[] p, const size_t size)
shared nothrow @nogc pure shared nothrow @nogc
{ {
if (p is null || size == 0) if (p is null || size == 0)
{ {
@ -368,7 +408,7 @@ final class MmapPool : Allocator
* *
* Returns: Whether the reallocation was successful. * Returns: Whether the reallocation was successful.
*/ */
bool reallocate(ref void[] p, const size_t size) shared nothrow @nogc bool reallocate(ref void[] p, const size_t size) shared pure nothrow @nogc
{ {
if (size == 0) if (size == 0)
{ {
@ -441,17 +481,17 @@ final class MmapPool : Allocator
// Get system dependend page size. // Get system dependend page size.
version (Posix) version (Posix)
{ {
pageSize = sysconf(_SC_PAGE_SIZE); pageSize_ = sysconf(_SC_PAGE_SIZE);
if (pageSize < 65536) if (pageSize_ < 65536)
{ {
pageSize = pageSize * 65536 / pageSize; pageSize_ = pageSize_ * 65536 / pageSize_;
} }
} }
else version (Windows) else version (Windows)
{ {
SYSTEM_INFO si; SYSTEM_INFO si;
GetSystemInfo(&si); GetSystemInfo(&si);
pageSize = si.dwPageSize; pageSize_ = si.dwPageSize;
} }
const instanceSize = addAlignment(__traits(classInstanceSize, const instanceSize = addAlignment(__traits(classInstanceSize,
@ -485,36 +525,18 @@ final class MmapPool : Allocator
* Returns: A pointer to the data. * Returns: A pointer to the data.
*/ */
private static void* initializeRegion(const size_t size, ref Region head) private static void* initializeRegion(const size_t size, ref Region head)
nothrow @nogc pure nothrow @nogc
{ {
const regionSize = calculateRegionSize(size); const regionSize = calculateRegionSize(size);
if (regionSize < size) if (regionSize < size)
{ {
return null; return null;
} }
version (Posix)
void* p = mapMemory(regionSize);
if (p is null)
{ {
void* p = mmap(null, return null;
regionSize,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON,
-1,
0);
if (p is MAP_FAILED)
{
return null;
}
}
else version (Windows)
{
void* p = VirtualAlloc(null,
regionSize,
MEM_COMMIT,
PAGE_READWRITE);
if (p is null)
{
return null;
}
} }
Region region = cast(Region) p; Region region = cast(Region) p;
@ -552,7 +574,7 @@ final class MmapPool : Allocator
return data; return data;
} }
private void* initializeRegion(const size_t size) shared nothrow @nogc private void* initializeRegion(const size_t size) shared pure nothrow @nogc
{ {
return initializeRegion(size, head); return initializeRegion(size, head);
} }
@ -575,7 +597,7 @@ final class MmapPool : Allocator
* Returns: Minimum region size (a multiple of $(D_PSYMBOL pageSize)). * Returns: Minimum region size (a multiple of $(D_PSYMBOL pageSize)).
*/ */
private static size_t calculateRegionSize(const size_t x) private static size_t calculateRegionSize(const size_t x)
nothrow @safe @nogc pure nothrow @safe @nogc
{ {
return (x + RegionEntry.sizeof + BlockEntry.sizeof * 2) return (x + RegionEntry.sizeof + BlockEntry.sizeof * 2)
/ pageSize * pageSize + pageSize; / pageSize * pageSize + pageSize;
@ -594,10 +616,18 @@ final class MmapPool : Allocator
assert(MmapPool.instance.alignment == MmapPool.alignment_); assert(MmapPool.instance.alignment == MmapPool.alignment_);
} }
private static @property size_t pageSize() pure nothrow @trusted @nogc
{
const pageSize = function size_t() nothrow @safe @nogc {
return pageSize_;
};
return (cast(size_t function() pure nothrow @safe @nogc) pageSize)();
}
private enum uint alignment_ = 8; private enum uint alignment_ = 8;
private shared static MmapPool instance_; private shared static MmapPool instance_;
private shared static size_t pageSize; private shared static size_t pageSize_;
private shared struct RegionEntry private shared struct RegionEntry
{ {