Use syscall instead of mmap and munmap

This commit is contained in:
Eugen Wissner 2018-04-22 08:07:20 +02:00
parent 5cac28c093
commit e8222123e6
6 changed files with 169 additions and 124 deletions

View File

@ -22,44 +22,31 @@ syscall1:
ret ret
.globl syscall2 // 2 parameters.
.type syscall2, @function .globl _D5tanya3sys5linux7syscall7syscallFNbNilllZl
.type _D5tanya3sys5linux7syscall7syscallFNbNilllZl, @function
syscall2: _D5tanya3sys5linux7syscall7syscallFNbNilllZl:
// Store registers. movq %rdx, %rax
movq %rdi, %r8
movq %rdx, %rax // Syscall number.
// Syscall arguments.
movq %rsi, %rdi
movq %r8, %rsi
syscall syscall
// Restore registers.
movq %rdi, %rsi
movq %r8, %rdi
ret ret
.globl syscall3 // 6 parameters.
.type syscall3, @function .globl _D5tanya3sys5linux7syscall7syscallFNbNilllllllZl
.type _D5tanya3sys5linux7syscall7syscallFNbNilllllllZl, @function
syscall3: _D5tanya3sys5linux7syscall7syscallFNbNilllllllZl:
// Store registers. pushq %rbp
movq %rdi, %r8 movq %rsp, %rbp
movq %rcx, %rax // Syscall number. movq 16(%rbp), %rax
// Syscall arguments. mov %rcx, %r10
movq %rdx, %rdi
movq %r8, %rdx
syscall syscall
// Restore registers. leave
movq %r8, %rdi
ret ret

View File

@ -35,7 +35,7 @@ interface Allocator
* *
* Returns: Pointer to the new allocated memory. * Returns: Pointer to the new allocated memory.
*/ */
void[] allocate(const size_t size) shared pure nothrow @nogc; void[] allocate(size_t size) shared pure nothrow @nogc;
/** /**
* Deallocates a memory block. * Deallocates a memory block.
@ -56,7 +56,7 @@ interface Allocator
* *
* Returns: Pointer to the allocated memory. * Returns: Pointer to the allocated memory.
*/ */
bool reallocate(ref void[] p, const size_t size) shared pure nothrow @nogc; bool reallocate(ref void[] p, size_t size) shared pure nothrow @nogc;
/** /**
* Reallocates a memory block in place if possible or returns * Reallocates a memory block in place if possible or returns
@ -70,7 +70,7 @@ interface 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, size_t size)
shared pure nothrow @nogc; shared pure nothrow @nogc;
} }

View File

@ -29,11 +29,11 @@ import tanya.memory.allocator;
final class Mallocator : Allocator final class Mallocator : Allocator
{ {
private alias MallocType = extern (C) void* function(size_t) private alias MallocType = extern (C) void* function(size_t)
pure nothrow @system @nogc; @nogc nothrow pure @system;
private alias FreeType = extern (C) void function(void*) private alias FreeType = extern (C) void function(void*)
pure nothrow @system @nogc; @nogc nothrow pure @system;
private alias ReallocType = extern (C) void* function(void*, size_t) private alias ReallocType = extern (C) void* function(void*, size_t)
pure nothrow @system @nogc; @nogc nothrow pure @system;
/** /**
* Allocates $(D_PARAM size) bytes of memory. * Allocates $(D_PARAM size) bytes of memory.
@ -43,7 +43,7 @@ final class Mallocator : Allocator
* *
* Returns: The pointer to the new allocated memory. * Returns: The pointer to the new allocated memory.
*/ */
void[] allocate(const size_t size) shared pure nothrow @nogc void[] allocate(size_t size) @nogc nothrow pure shared @system
{ {
if (size == 0) if (size == 0)
{ {
@ -55,7 +55,7 @@ final class Mallocator : Allocator
} }
/// ///
@nogc nothrow unittest @nogc nothrow pure @system unittest
{ {
auto p = Mallocator.instance.allocate(20); auto p = Mallocator.instance.allocate(20);
assert(p.length == 20); assert(p.length == 20);
@ -73,7 +73,7 @@ final class Mallocator : Allocator
* *
* Returns: Whether the deallocation was successful. * Returns: Whether the deallocation was successful.
*/ */
bool deallocate(void[] p) shared pure nothrow @nogc bool deallocate(void[] p) @nogc nothrow pure shared @system
{ {
if (p !is null) if (p !is null)
{ {
@ -83,7 +83,7 @@ final class Mallocator : Allocator
} }
/// ///
@nogc nothrow unittest @nogc nothrow pure @system unittest
{ {
void[] p; void[] p;
assert(Mallocator.instance.deallocate(p)); assert(Mallocator.instance.deallocate(p));
@ -101,14 +101,14 @@ final class Mallocator : Allocator
* *
* Returns: $(D_KEYWORD false). * Returns: $(D_KEYWORD false).
*/ */
bool reallocateInPlace(ref void[] p, const size_t size) bool reallocateInPlace(ref void[] p, size_t size)
shared pure nothrow @nogc @nogc nothrow pure shared @system
{ {
return false; return false;
} }
/// ///
@nogc nothrow unittest @nogc nothrow pure @system unittest
{ {
void[] p; void[] p;
assert(!Mallocator.instance.reallocateInPlace(p, 8)); assert(!Mallocator.instance.reallocateInPlace(p, 8));
@ -123,7 +123,8 @@ final class Mallocator : Allocator
* *
* Returns: Whether the reallocation was successful. * Returns: Whether the reallocation was successful.
*/ */
bool reallocate(ref void[] p, const size_t size) shared pure nothrow @nogc bool reallocate(ref void[] p, size_t size)
@nogc nothrow pure shared @system
{ {
if (size == 0) if (size == 0)
{ {
@ -152,7 +153,7 @@ final class Mallocator : Allocator
} }
/// ///
@nogc nothrow unittest @nogc nothrow pure @system unittest
{ {
void[] p; void[] p;
@ -169,8 +170,8 @@ final class Mallocator : Allocator
assert(p is null); assert(p is null);
} }
// Fails with false. // Fails with false
private @nogc nothrow unittest @nogc nothrow pure @system unittest
{ {
void[] p = Mallocator.instance.allocate(20); void[] p = Mallocator.instance.allocate(20);
void[] oldP = p; void[] oldP = p;
@ -182,7 +183,7 @@ final class Mallocator : Allocator
/** /**
* Returns: The alignment offered. * Returns: The alignment offered.
*/ */
@property uint alignment() shared const pure nothrow @safe @nogc @property uint alignment() const @nogc nothrow pure @safe shared
{ {
return (void*).alignof; return (void*).alignof;
} }
@ -192,7 +193,7 @@ final class Mallocator : Allocator
assert(Mallocator.instance.alignment == (void*).alignof); assert(Mallocator.instance.alignment == (void*).alignof);
} }
static private shared(Mallocator) instantiate() nothrow @nogc static private shared(Mallocator) instantiate() @nogc nothrow @system
{ {
if (instance_ is null) if (instance_ is null)
{ {
@ -213,13 +214,13 @@ final class Mallocator : Allocator
* *
* Returns: The global $(D_PSYMBOL Allocator) instance. * Returns: The global $(D_PSYMBOL Allocator) instance.
*/ */
static @property shared(Mallocator) instance() pure nothrow @nogc static @property shared(Mallocator) instance() @nogc nothrow pure @system
{ {
return (cast(GetPureInstance!Mallocator) &instantiate)(); return (cast(GetPureInstance!Mallocator) &instantiate)();
} }
/// ///
@nogc nothrow unittest @nogc nothrow pure @system unittest
{ {
assert(instance is instance); assert(instance is instance);
} }

View File

@ -14,45 +14,32 @@
*/ */
module tanya.memory.mmappool; module tanya.memory.mmappool;
import std.algorithm.comparison;
import tanya.memory.allocator;
import tanya.memory.op;
version (TanyaNative): version (TanyaNative):
import core.sys.posix.sys.mman : MAP_ANON, import mir.linux._asm.unistd;
MAP_FAILED, import tanya.algorithm.comparison;
MAP_PRIVATE, import tanya.memory.allocator;
PROT_READ, import tanya.memory.op;
PROT_WRITE; import tanya.os.error;
import core.sys.posix.unistd; import tanya.sys.linux.syscall;
import tanya.sys.posix.mman;
extern(C) private void* mapMemory(const size_t length) @nogc nothrow pure @system
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, auto p = syscall_(0,
len, length,
PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, MAP_PRIVATE | MAP_ANONYMOUS,
-1, -1,
0); 0,
return p is MAP_FAILED ? null : p; NR_mmap);
return p == -ErrorCode.noMemory ? null : cast(void*) p;
} }
private bool unmapMemory(shared void* addr, const size_t len) private bool unmapMemory(shared void* addr, const size_t length)
pure nothrow @system @nogc @nogc nothrow pure @system
{ {
return munmap(cast(void*) addr, len) == 0; return syscall_(cast(ptrdiff_t) addr, length, NR_munmap) == 0;
} }
/* /*
@ -83,7 +70,7 @@ final class MmapPool : Allocator
{ {
version (none) version (none)
{ {
pure nothrow @nogc invariant @nogc nothrow pure @system invariant
{ {
for (auto r = &head; *r !is null; r = &((*r).next)) for (auto r = &head; *r !is null; r = &((*r).next))
{ {
@ -107,7 +94,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 pure nothrow @nogc void[] allocate(size_t size) @nogc nothrow pure shared @system
{ {
if (size == 0) if (size == 0)
{ {
@ -128,7 +115,7 @@ final class MmapPool : Allocator
return data is null ? null : data[0 .. size]; return data is null ? null : data[0 .. size];
} }
@nogc nothrow pure unittest @nogc nothrow pure @system unittest
{ {
auto p = MmapPool.instance.allocate(20); auto p = MmapPool.instance.allocate(20);
assert(p); assert(p);
@ -138,15 +125,14 @@ final class MmapPool : Allocator
assert(p.length == 0); assert(p.length == 0);
} }
// Issue 245: https://issues.caraus.io/issues/245. @nogc nothrow pure @system unittest
@nogc nothrow pure unittest
{ {
// allocate() check. // allocate() check.
size_t tooMuchMemory = size_t.max size_t tooMuchMemory = size_t.max
- MmapPool.alignment_ - MmapPool.alignment_
- BlockEntry.sizeof * 2 - BlockEntry.sizeof * 2
- RegionEntry.sizeof - RegionEntry.sizeof
- MmapPool.instance.pageSize; - pageSize;
assert(MmapPool.instance.allocate(tooMuchMemory) is null); assert(MmapPool.instance.allocate(tooMuchMemory) is null);
assert(MmapPool.instance.allocate(size_t.max) is null); assert(MmapPool.instance.allocate(size_t.max) is null);
@ -165,7 +151,8 @@ 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 pure nothrow @nogc private void* findBlock(const ref size_t size)
@nogc nothrow pure shared @system
{ {
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)
@ -207,7 +194,7 @@ final class MmapPool : Allocator
} }
// Merge block with the next one. // Merge block with the next one.
private void mergeNext(Block block) shared const pure nothrow @safe @nogc private void mergeNext(Block block) const @nogc nothrow pure @safe shared
{ {
block.size = block.size + BlockEntry.sizeof + block.next.size; block.size = block.size + BlockEntry.sizeof + block.next.size;
if (block.next.next !is null) if (block.next.next !is null)
@ -225,7 +212,7 @@ final class MmapPool : Allocator
* *
* Returns: Whether the deallocation was successful. * Returns: Whether the deallocation was successful.
*/ */
bool deallocate(void[] p) shared pure nothrow @nogc bool deallocate(void[] p) @nogc nothrow pure shared @system
{ {
if (p.ptr is null) if (p.ptr is null)
{ {
@ -271,7 +258,7 @@ final class MmapPool : Allocator
return true; return true;
} }
@nogc nothrow pure unittest @nogc nothrow pure @system unittest
{ {
auto p = MmapPool.instance.allocate(20); auto p = MmapPool.instance.allocate(20);
@ -290,8 +277,8 @@ 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, size_t size)
shared pure nothrow @nogc @nogc nothrow pure shared @system
{ {
if (p is null || size == 0) if (p is null || size == 0)
{ {
@ -354,7 +341,7 @@ final class MmapPool : Allocator
return true; return true;
} }
@nogc nothrow pure unittest @nogc nothrow pure @system unittest
{ {
void[] p; void[] p;
assert(!MmapPool.instance.reallocateInPlace(p, 5)); assert(!MmapPool.instance.reallocateInPlace(p, 5));
@ -387,7 +374,8 @@ 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 pure nothrow @nogc bool reallocate(ref void[] p, size_t size)
@nogc nothrow pure shared @system
{ {
if (size == 0) if (size == 0)
{ {
@ -419,7 +407,7 @@ final class MmapPool : Allocator
return true; return true;
} }
@nogc nothrow pure unittest @nogc nothrow pure @system unittest
{ {
void[] p; void[] p;
MmapPool.instance.reallocate(p, 10 * int.sizeof); MmapPool.instance.reallocate(p, 10 * int.sizeof);
@ -447,28 +435,20 @@ final class MmapPool : Allocator
MmapPool.instance.deallocate(p); MmapPool.instance.deallocate(p);
} }
static private shared(MmapPool) instantiate() nothrow @nogc static private shared(MmapPool) instantiate() @nogc nothrow @system
{ {
if (instance_ is null) if (instance_ is null)
{ {
// Get system dependend page size.
size_t pageSize = sysconf(_SC_PAGE_SIZE);
if (pageSize < 65536)
{
pageSize = pageSize * 65536 / pageSize;
}
const instanceSize = addAlignment(__traits(classInstanceSize, const instanceSize = addAlignment(__traits(classInstanceSize,
MmapPool)); MmapPool));
Region head; // Will become soon our region list head Region head; // Will become soon our region list head
void* data = initializeRegion(instanceSize, head, pageSize); void* data = initializeRegion(instanceSize, head);
if (data !is null) if (data !is null)
{ {
copy(typeid(MmapPool).initializer, data[0 .. instanceSize]); copy(typeid(MmapPool).initializer, data[0 .. instanceSize]);
instance_ = cast(shared MmapPool) data; instance_ = cast(shared MmapPool) data;
instance_.head = head; instance_.head = head;
instance_.pageSize = pageSize;
} }
} }
return instance_; return instance_;
@ -479,12 +459,12 @@ final class MmapPool : Allocator
* *
* Returns: Global $(D_PSYMBOL MmapPool) instance. * Returns: Global $(D_PSYMBOL MmapPool) instance.
*/ */
static @property shared(MmapPool) instance() pure nothrow @nogc static @property shared(MmapPool) instance() @nogc nothrow pure @system
{ {
return (cast(GetPureInstance!MmapPool) &instantiate)(); return (cast(GetPureInstance!MmapPool) &instantiate)();
} }
@nogc nothrow pure unittest @nogc nothrow pure @system unittest
{ {
assert(instance is instance); assert(instance is instance);
} }
@ -498,12 +478,10 @@ final class MmapPool : Allocator
* *
* Returns: A pointer to the data. * Returns: A pointer to the data.
*/ */
private static void* initializeRegion(const size_t size, private static void* initializeRegion(const size_t size, ref Region head)
ref Region head, @nogc nothrow pure @system
const size_t pageSize)
pure nothrow @nogc
{ {
const regionSize = calculateRegionSize(size, pageSize); const regionSize = calculateRegionSize(size);
if (regionSize < size) if (regionSize < size)
{ {
return null; return null;
@ -550,9 +528,10 @@ final class MmapPool : Allocator
return data; return data;
} }
private void* initializeRegion(const size_t size) shared pure nothrow @nogc private void* initializeRegion(const size_t size)
@nogc nothrow pure shared @system
{ {
return initializeRegion(size, this.head, this.pageSize); return initializeRegion(size, this.head);
} }
/* /*
@ -561,21 +540,19 @@ final class MmapPool : Allocator
* *
* Returns: Aligned size of $(D_PARAM x). * Returns: Aligned size of $(D_PARAM x).
*/ */
private static size_t addAlignment(const size_t x) pure nothrow @safe @nogc private static size_t addAlignment(const size_t x) @nogc nothrow pure @safe
{ {
return (x - 1) / alignment_ * alignment_ + alignment_; return (x - 1) / alignment_ * alignment_ + alignment_;
} }
/* /*
* Params: * Params:
* x = Required space. * x = Required space.
* pageSize = Page size.
* *
* 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(ref const size_t x, private static size_t calculateRegionSize(ref const size_t x)
ref const size_t pageSize) @nogc nothrow pure @safe
pure nothrow @safe @nogc
{ {
return (x + RegionEntry.sizeof + BlockEntry.sizeof * 2) return (x + RegionEntry.sizeof + BlockEntry.sizeof * 2)
/ pageSize * pageSize + pageSize; / pageSize * pageSize + pageSize;
@ -584,12 +561,12 @@ final class MmapPool : Allocator
/* /*
* Returns: Alignment offered. * Returns: Alignment offered.
*/ */
@property uint alignment() shared const pure nothrow @safe @nogc @property uint alignment() const @nogc nothrow pure @safe shared
{ {
return alignment_; return alignment_;
} }
@nogc nothrow pure unittest @nogc nothrow pure @system unittest
{ {
assert(MmapPool.instance.alignment == MmapPool.alignment_); assert(MmapPool.instance.alignment == MmapPool.alignment_);
} }
@ -597,7 +574,9 @@ final class MmapPool : Allocator
private enum uint alignment_ = 8; private enum uint alignment_ = 8;
private shared static MmapPool instance_; private shared static MmapPool instance_;
private shared size_t pageSize;
// Page size.
enum size_t pageSize = 65536;
private shared struct RegionEntry private shared struct RegionEntry
{ {
@ -622,7 +601,7 @@ final class MmapPool : Allocator
// A lot of allocations/deallocations, but it is the minimum caused a // A lot of allocations/deallocations, but it is the minimum caused a
// segmentation fault because MmapPool reallocateInPlace moves a block wrong. // segmentation fault because MmapPool reallocateInPlace moves a block wrong.
@nogc nothrow pure unittest @nogc nothrow pure @system unittest
{ {
auto a = MmapPool.instance.allocate(16); auto a = MmapPool.instance.allocate(16);
auto d = MmapPool.instance.allocate(16); auto d = MmapPool.instance.allocate(16);

View File

@ -0,0 +1,47 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Copyright: Eugene Wissner 2018.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/linux/syscall.d,
* tanya/sys/linux/syscall.d)
*/
module tanya.sys.linux.syscall;
version (TanyaNative):
extern ptrdiff_t syscall(ptrdiff_t, ptrdiff_t, ptrdiff_t)
@nogc nothrow @system;
extern ptrdiff_t syscall(ptrdiff_t,
ptrdiff_t,
ptrdiff_t,
ptrdiff_t,
ptrdiff_t,
ptrdiff_t,
ptrdiff_t) @nogc nothrow @system;
// Same syscalls as above but pure.
private template getOverloadMangling(size_t n)
{
enum string getOverloadMangling = __traits(getOverloads,
tanya.sys.linux.syscall,
"syscall")[n].mangleof;
}
pragma(mangle, getOverloadMangling!0)
extern ptrdiff_t syscall_(ptrdiff_t, ptrdiff_t, ptrdiff_t)
@nogc nothrow pure @system;
pragma(mangle, getOverloadMangling!1)
extern ptrdiff_t syscall_(ptrdiff_t,
ptrdiff_t,
ptrdiff_t,
ptrdiff_t,
ptrdiff_t,
ptrdiff_t,
ptrdiff_t) @nogc nothrow pure @system;

View File

@ -0,0 +1,31 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Copyright: Eugene Wissner 2018.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/posix/mman.d,
* tanya/sys/posix/mman.d)
*/
module tanya.sys.posix.mman;
version (TanyaNative):
enum
{
PROT_EXEC = 0x4, // Page can be executed.
PROT_NONE = 0x0, // Page cannot be accessed.
PROT_READ = 0x1, // Page can be read.
PROT_WRITE = 0x2, // Page can be written.
}
enum
{
MAP_FIXED = 0x10, // Interpret addr exactly.
MAP_PRIVATE = 0x02, // Changes are private.
MAP_SHARED = 0x01, // Share changes.
MAP_ANONYMOUS = 0x20, // Don't use a file.
}