diff --git a/arch/x64/linux/syscall.S b/arch/x64/linux/syscall.S index 9261d87..7c00036 100644 --- a/arch/x64/linux/syscall.S +++ b/arch/x64/linux/syscall.S @@ -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 diff --git a/source/tanya/memory/allocator.d b/source/tanya/memory/allocator.d index 0eaff65..1d8139d 100644 --- a/source/tanya/memory/allocator.d +++ b/source/tanya/memory/allocator.d @@ -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; } diff --git a/source/tanya/memory/mallocator.d b/source/tanya/memory/mallocator.d index ce868b8..f9e65cd 100644 --- a/source/tanya/memory/mallocator.d +++ b/source/tanya/memory/mallocator.d @@ -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); } diff --git a/source/tanya/memory/mmappool.d b/source/tanya/memory/mmappool.d index b555580..fb3ef06 100644 --- a/source/tanya/memory/mmappool.d +++ b/source/tanya/memory/mmappool.d @@ -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); diff --git a/source/tanya/sys/linux/syscall.d b/source/tanya/sys/linux/syscall.d new file mode 100644 index 0000000..64d2cd4 --- /dev/null +++ b/source/tanya/sys/linux/syscall.d @@ -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; diff --git a/source/tanya/sys/posix/mman.d b/source/tanya/sys/posix/mman.d new file mode 100644 index 0000000..dbf78a9 --- /dev/null +++ b/source/tanya/sys/posix/mman.d @@ -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. +}