1 /** 2 Copyright: Copyright (c) 2017-2019 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 module vox.utils.arenapool; 7 8 version(Posix) extern (C) int getpagesize(); 9 10 // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mmap.2.html 11 // https://stackoverflow.com/questions/21809072/virtual-memory-on-osx-ios-versus-windows-commit-reserve-behaviour 12 13 /// 14 struct ArenaPool 15 { 16 import vox.utils : alignValue; 17 import std.format; 18 import std.stdio; 19 import std.string : fromStringz; 20 import core.stdc.errno : errno; 21 import core.stdc.string : strerror; 22 23 enum PAGE_SIZE = 65_536; 24 ubyte[] buffer; 25 size_t takenBytes; 26 27 void reserve(size_t size) { 28 size_t reservedBytes = alignValue(size, PAGE_SIZE); // round up to page size 29 version(Posix) { 30 import core.sys.posix.sys.mman : mmap, MAP_ANON, PROT_READ, PROT_WRITE, PROT_EXEC, MAP_PRIVATE, MAP_FAILED; 31 enum MAP_NORESERVE = 0x4000; 32 auto flags = MAP_PRIVATE | MAP_ANON; 33 // MacOS doesn't support MAP_NORESERVE. See https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mmap.2.html 34 version(linux) flags |= MAP_NORESERVE; 35 ubyte* ptr = cast(ubyte*)mmap(null, reservedBytes, PROT_READ | PROT_WRITE, flags, -1, 0); 36 assert(ptr != MAP_FAILED, format("mmap failed, errno %s, %s: requested %s bytes", errno, strerror(errno).fromStringz, size)); 37 } else version(Windows) { 38 import vox.utils.windows : VirtualAlloc, MEM_RESERVE, PAGE_NOACCESS; 39 ubyte* ptr = cast(ubyte*)VirtualAlloc(null, reservedBytes, MEM_RESERVE, PAGE_NOACCESS); 40 assert(ptr !is null, format("VirtualAlloc failed: requested %s bytes", size)); 41 } 42 buffer = ptr[0..reservedBytes]; 43 } 44 45 ubyte[] take(size_t numBytes) { 46 if (numBytes == 0) return null; 47 ubyte[] result = buffer[takenBytes..takenBytes+numBytes]; 48 takenBytes += numBytes; 49 return result; 50 } 51 52 void decommitAll() { 53 version(Posix) { 54 import core.sys.posix.sys.mman : munmap; 55 if (buffer.ptr is null) return; 56 int res = munmap(buffer.ptr, buffer.length); 57 assert(res == 0, format("munmap(%X, %s) failed, %s, %s", buffer.ptr, buffer.length, errno, strerror(errno).fromStringz)); 58 } else version(Windows) { 59 import vox.utils.windows : VirtualFree, MEM_DECOMMIT; 60 int res = VirtualFree(buffer.ptr, buffer.length, MEM_DECOMMIT); 61 assert(res != 0, "VirtualFree failed"); 62 } 63 } 64 }