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
.globl syscall2
.type syscall2, @function
// 2 parameters.
.globl _D5tanya3sys5linux7syscall7syscallFNbNilllZl
.type _D5tanya3sys5linux7syscall7syscallFNbNilllZl, @function
syscall2:
// Store registers.
movq %rdi, %r8
movq %rdx, %rax // Syscall number.
// Syscall arguments.
movq %rsi, %rdi
movq %r8, %rsi
_D5tanya3sys5linux7syscall7syscallFNbNilllZl:
movq %rdx, %rax
syscall
// Restore registers.
movq %rdi, %rsi
movq %r8, %rdi
ret
.globl syscall3
.type syscall3, @function
// 6 parameters.
.globl _D5tanya3sys5linux7syscall7syscallFNbNilllllllZl
.type _D5tanya3sys5linux7syscall7syscallFNbNilllllllZl, @function
syscall3:
// Store registers.
movq %rdi, %r8
_D5tanya3sys5linux7syscall7syscallFNbNilllllllZl:
pushq %rbp
movq %rsp, %rbp
movq %rcx, %rax // Syscall number.
movq 16(%rbp), %rax
// Syscall arguments.
movq %rdx, %rdi
movq %r8, %rdx
mov %rcx, %r10
syscall
// Restore registers.
movq %r8, %rdi
leave
ret

View File

@ -35,7 +35,7 @@ interface Allocator
*
* 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.
@ -56,7 +56,7 @@ interface Allocator
*
* 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
@ -70,7 +70,7 @@ interface Allocator
*
* 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;
}

View File

@ -29,11 +29,11 @@ import tanya.memory.allocator;
final class Mallocator : Allocator
{
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*)
pure nothrow @system @nogc;
@nogc nothrow pure @system;
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.
@ -43,7 +43,7 @@ final class Mallocator : Allocator
*
* 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)
{
@ -55,7 +55,7 @@ final class Mallocator : Allocator
}
///
@nogc nothrow unittest
@nogc nothrow pure @system unittest
{
auto p = Mallocator.instance.allocate(20);
assert(p.length == 20);
@ -73,7 +73,7 @@ final class Mallocator : Allocator
*
* 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)
{
@ -83,7 +83,7 @@ final class Mallocator : Allocator
}
///
@nogc nothrow unittest
@nogc nothrow pure @system unittest
{
void[] p;
assert(Mallocator.instance.deallocate(p));
@ -101,14 +101,14 @@ final class Mallocator : Allocator
*
* Returns: $(D_KEYWORD false).
*/
bool reallocateInPlace(ref void[] p, const size_t size)
shared pure nothrow @nogc
bool reallocateInPlace(ref void[] p, size_t size)
@nogc nothrow pure shared @system
{
return false;
}
///
@nogc nothrow unittest
@nogc nothrow pure @system unittest
{
void[] p;
assert(!Mallocator.instance.reallocateInPlace(p, 8));
@ -123,7 +123,8 @@ final class Mallocator : Allocator
*
* 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)
{
@ -152,7 +153,7 @@ final class Mallocator : Allocator
}
///
@nogc nothrow unittest
@nogc nothrow pure @system unittest
{
void[] p;
@ -169,8 +170,8 @@ final class Mallocator : Allocator
assert(p is null);
}
// Fails with false.
private @nogc nothrow unittest
// Fails with false
@nogc nothrow pure @system unittest
{
void[] p = Mallocator.instance.allocate(20);
void[] oldP = p;
@ -182,7 +183,7 @@ final class Mallocator : Allocator
/**
* 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;
}
@ -192,7 +193,7 @@ final class Mallocator : Allocator
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)
{
@ -213,13 +214,13 @@ final class Mallocator : Allocator
*
* 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)();
}
///
@nogc nothrow unittest
@nogc nothrow pure @system unittest
{
assert(instance is instance);
}

View File

@ -14,45 +14,32 @@
*/
module tanya.memory.mmappool;
import std.algorithm.comparison;
import tanya.memory.allocator;
import tanya.memory.op;
version (TanyaNative):
import core.sys.posix.sys.mman : MAP_ANON,
MAP_FAILED,
MAP_PRIVATE,
PROT_READ,
PROT_WRITE;
import core.sys.posix.unistd;
import mir.linux._asm.unistd;
import tanya.algorithm.comparison;
import tanya.memory.allocator;
import tanya.memory.op;
import tanya.os.error;
import tanya.sys.linux.syscall;
import tanya.sys.posix.mman;
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
private void* mapMemory(const size_t length) @nogc nothrow pure @system
{
void* p = mmap(null,
len,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON,
-1,
0);
return p is MAP_FAILED ? null : p;
auto p = syscall_(0,
length,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1,
0,
NR_mmap);
return p == -ErrorCode.noMemory ? null : cast(void*) p;
}
private bool unmapMemory(shared void* addr, const size_t len)
pure nothrow @system @nogc
private bool unmapMemory(shared void* addr, const size_t length)
@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)
{
pure nothrow @nogc invariant
@nogc nothrow pure @system invariant
{
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.
*/
void[] allocate(const size_t size) shared pure nothrow @nogc
void[] allocate(size_t size) @nogc nothrow pure shared @system
{
if (size == 0)
{
@ -128,7 +115,7 @@ final class MmapPool : Allocator
return data is null ? null : data[0 .. size];
}
@nogc nothrow pure unittest
@nogc nothrow pure @system unittest
{
auto p = MmapPool.instance.allocate(20);
assert(p);
@ -138,15 +125,14 @@ final class MmapPool : Allocator
assert(p.length == 0);
}
// Issue 245: https://issues.caraus.io/issues/245.
@nogc nothrow pure unittest
@nogc nothrow pure @system unittest
{
// allocate() check.
size_t tooMuchMemory = size_t.max
- MmapPool.alignment_
- BlockEntry.sizeof * 2
- RegionEntry.sizeof
- MmapPool.instance.pageSize;
- pageSize;
assert(MmapPool.instance.allocate(tooMuchMemory) 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).
*/
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;
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.
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;
if (block.next.next !is null)
@ -225,7 +212,7 @@ final class MmapPool : Allocator
*
* 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)
{
@ -271,7 +258,7 @@ final class MmapPool : Allocator
return true;
}
@nogc nothrow pure unittest
@nogc nothrow pure @system unittest
{
auto p = MmapPool.instance.allocate(20);
@ -290,8 +277,8 @@ final class MmapPool : Allocator
*
* Returns: $(D_KEYWORD true) if successful, $(D_KEYWORD false) otherwise.
*/
bool reallocateInPlace(ref void[] p, const size_t size)
shared pure nothrow @nogc
bool reallocateInPlace(ref void[] p, size_t size)
@nogc nothrow pure shared @system
{
if (p is null || size == 0)
{
@ -354,7 +341,7 @@ final class MmapPool : Allocator
return true;
}
@nogc nothrow pure unittest
@nogc nothrow pure @system unittest
{
void[] p;
assert(!MmapPool.instance.reallocateInPlace(p, 5));
@ -387,7 +374,8 @@ final class MmapPool : Allocator
*
* 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)
{
@ -419,7 +407,7 @@ final class MmapPool : Allocator
return true;
}
@nogc nothrow pure unittest
@nogc nothrow pure @system unittest
{
void[] p;
MmapPool.instance.reallocate(p, 10 * int.sizeof);
@ -447,28 +435,20 @@ final class MmapPool : Allocator
MmapPool.instance.deallocate(p);
}
static private shared(MmapPool) instantiate() nothrow @nogc
static private shared(MmapPool) instantiate() @nogc nothrow @system
{
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,
MmapPool));
Region head; // Will become soon our region list head
void* data = initializeRegion(instanceSize, head, pageSize);
void* data = initializeRegion(instanceSize, head);
if (data !is null)
{
copy(typeid(MmapPool).initializer, data[0 .. instanceSize]);
instance_ = cast(shared MmapPool) data;
instance_.head = head;
instance_.pageSize = pageSize;
}
}
return instance_;
@ -479,12 +459,12 @@ final class MmapPool : Allocator
*
* 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)();
}
@nogc nothrow pure unittest
@nogc nothrow pure @system unittest
{
assert(instance is instance);
}
@ -498,12 +478,10 @@ final class MmapPool : Allocator
*
* Returns: A pointer to the data.
*/
private static void* initializeRegion(const size_t size,
ref Region head,
const size_t pageSize)
pure nothrow @nogc
private static void* initializeRegion(const size_t size, ref Region head)
@nogc nothrow pure @system
{
const regionSize = calculateRegionSize(size, pageSize);
const regionSize = calculateRegionSize(size);
if (regionSize < size)
{
return null;
@ -550,9 +528,10 @@ final class MmapPool : Allocator
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).
*/
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_;
}
/*
* Params:
* x = Required space.
* pageSize = Page size.
* x = Required space.
*
* Returns: Minimum region size (a multiple of $(D_PSYMBOL pageSize)).
*/
private static size_t calculateRegionSize(ref const size_t x,
ref const size_t pageSize)
pure nothrow @safe @nogc
private static size_t calculateRegionSize(ref const size_t x)
@nogc nothrow pure @safe
{
return (x + RegionEntry.sizeof + BlockEntry.sizeof * 2)
/ pageSize * pageSize + pageSize;
@ -584,12 +561,12 @@ final class MmapPool : Allocator
/*
* Returns: Alignment offered.
*/
@property uint alignment() shared const pure nothrow @safe @nogc
@property uint alignment() const @nogc nothrow pure @safe shared
{
return alignment_;
}
@nogc nothrow pure unittest
@nogc nothrow pure @system unittest
{
assert(MmapPool.instance.alignment == MmapPool.alignment_);
}
@ -597,7 +574,9 @@ final class MmapPool : Allocator
private enum uint alignment_ = 8;
private shared static MmapPool instance_;
private shared size_t pageSize;
// Page size.
enum size_t pageSize = 65536;
private shared struct RegionEntry
{
@ -622,7 +601,7 @@ final class MmapPool : Allocator
// A lot of allocations/deallocations, but it is the minimum caused a
// 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 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.
}