From 7cd8eb0a43351b853430214e79b564403fa97b65 Mon Sep 17 00:00:00 2001 From: jyelon Date: Mon, 28 Feb 2022 21:57:54 -0500 Subject: [PATCH] Lots more work on eng::malloc --- luprex/core/Makefile | 2 +- luprex/core/cpp/driver-linux.cpp | 1 - luprex/core/cpp/eng-malloc.cpp | 122 ++++++++++++++++++ luprex/core/cpp/eng-malloc.hpp | 152 +++++++++++++++++++++++ luprex/core/cpp/eng-tests.cpp | 2 +- luprex/core/cpp/lpxserver.cpp | 2 +- luprex/core/cpp/luaconsole.cpp | 4 +- luprex/core/cpp/luasnap.cpp | 2 +- luprex/core/cpp/luastack.cpp | 16 ++- luprex/core/cpp/printbuffer.cpp | 2 +- luprex/core/cpp/printbuffer.hpp | 4 +- luprex/core/cpp/source.cpp | 2 +- luprex/core/cpp/streambuffer.cpp | 12 +- luprex/core/cpp/two-mallocs.cpp | 64 ---------- luprex/core/cpp/two-mallocs.hpp | 157 ------------------------ luprex/core/wrap/mkstub.py | 2 +- luprex/core/wrap/wrap-deque.hpp | 2 +- luprex/core/wrap/wrap-map.hpp | 2 +- luprex/core/wrap/wrap-set.hpp | 2 +- luprex/core/wrap/wrap-sstream.hpp | 2 +- luprex/core/wrap/wrap-string.hpp | 2 +- luprex/core/wrap/wrap-unordered-map.hpp | 2 +- luprex/core/wrap/wrap-unordered-set.hpp | 2 +- luprex/core/wrap/wrap-vector.hpp | 2 +- luprex/linuxlib/dlmalloc/dlmalloc.c | 5 +- 25 files changed, 314 insertions(+), 253 deletions(-) create mode 100644 luprex/core/cpp/eng-malloc.cpp create mode 100644 luprex/core/cpp/eng-malloc.hpp delete mode 100644 luprex/core/cpp/two-mallocs.cpp delete mode 100644 luprex/core/cpp/two-mallocs.hpp diff --git a/luprex/core/Makefile b/luprex/core/Makefile index 1ee9894f..1d8ea952 100644 --- a/luprex/core/Makefile +++ b/luprex/core/Makefile @@ -65,7 +65,7 @@ LUA_OBJ_FILES=\ CORE_OBJ_FILES=\ obj/invocation.o\ obj/spookyv2.o\ - obj/two-mallocs.o\ + obj/eng-malloc.o\ obj/debugcollector.o\ obj/drivenengine.o\ obj/dummycert.o\ diff --git a/luprex/core/cpp/driver-linux.cpp b/luprex/core/cpp/driver-linux.cpp index 268d109b..ccaf479f 100644 --- a/luprex/core/cpp/driver-linux.cpp +++ b/luprex/core/cpp/driver-linux.cpp @@ -263,7 +263,6 @@ public: int main(int argc, char **argv) { - mallopt(M_MMAP_MAX, 0); // Keep malloc in the 'brk' area. disable_randomization(argc, argv); allocate_buffers(); enable_tty_raw(); diff --git a/luprex/core/cpp/eng-malloc.cpp b/luprex/core/cpp/eng-malloc.cpp new file mode 100644 index 00000000..bccc6c38 --- /dev/null +++ b/luprex/core/cpp/eng-malloc.cpp @@ -0,0 +1,122 @@ + +// We only use a custom allocator on linux (for now) +// The allocator we chose is 'dlmalloc' (doug lea's malloc). +// It's a good allocator for single-threaded programs. +// It needs to be configured by setting a bunch of defines. +// +#ifdef __linux__ + +// We need this to define dlmalloc, not malloc. +#define USE_DL_PREFIX 1 + +// We don't need mspaces. +#define ONLY_MSPACES 0 +#define MSPACES 0 + +// We don't need mallinfo +#define NO_MALLINFO 1 + +// We don't need dlmalloc_inspect_all +#define MALLOC_INSPECT_ALL 0 + +// Disable locking. The entire engine is single-threaded. +#define USE_LOCKS 0 + +// This allocator can use sbrk to obtain RAM. We're going to +// emulate sbrk, in order to put it in a different memory region +// than the system malloc, which also uses sbrk. +#define HAVE_MORECORE 1 +#define MORECORE emulated_sbrk +#define MORECORE_CANNOT_TRIM 1 + +// We won't let the memory allocator use mmap. This is because +// opening the replay log may be implemented in stdio using mmap. +// So using mmap might trigger different results under replay. +#define HAVE_MMAP 0 + +// Fix a warning in dlmalloc. +#define MAX_RELEASE_CHECK_RATE INT_MAX + +// Don't generate random seeds, or time-based seeds. +#define USE_DEV_RANDOM 0 +#define LACKS_TIME_H 1 + +// Don't export any dlmalloc functions. +#define DLMALLOC_EXPORT static inline + +#include +#include +#include +#include + +static char *emulated_sbrk_base; +static intptr_t emulated_sbrk_used; +static intptr_t emulated_sbrk_limit; + +// We assume that the increments are already aligned to the system +// page size, because dlmalloc does that for us. +// +// Our emulated sbrk cannot trim the memory size. It can only grow. +// +static void *emulated_sbrk(intptr_t increment) { + if (emulated_sbrk_base == 0) { + emulated_sbrk_limit = intptr_t(64) * 1024 * 1024 * 1024; + void *map = mmap(nullptr, emulated_sbrk_limit, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(map != MAP_FAILED); + assert(map != nullptr); + emulated_sbrk_base = (char *)map; + emulated_sbrk_used = 0; + } + int64_t old_used = emulated_sbrk_used; + int64_t new_used = emulated_sbrk_used + increment; + if (new_used > emulated_sbrk_limit) { + return (void *)(-1); + } + assert(new_used >= old_used); + emulated_sbrk_used = new_used; + if (new_used > old_used) { + int status = mprotect(emulated_sbrk_base + old_used, new_used - old_used, PROT_READ | PROT_WRITE); + assert(status == 0); + } + return emulated_sbrk_base + old_used; +} + +#include "dlmalloc/dlmalloc.c" + +namespace eng { + static uint32_t hash; + void *malloc(size_t size) { + void *result = dlmalloc(size); + hash += uint32_t(uintptr_t(result)) + 0x83748374; + hash += hash << 10; + hash ^= hash >> 6; + hash += uint32_t(size) + 0x85893489; + hash += hash << 10; + hash ^= hash >> 6; + return result; + } + void *realloc(void *p, size_t size) { + void *result = dlrealloc(p, size); + hash += uint32_t(uintptr_t(p)) + 0x74741912; + hash += hash << 10; + hash ^= hash >> 6; + hash += uint32_t(uintptr_t(result)) + 0x68843823; + hash += hash << 10; + hash ^= hash >> 6; + hash += uint32_t(size) + 0x81444120; + hash += hash << 10; + hash ^= hash >> 6; + return result; + } + void free(void *p) { + hash += uint32_t(uintptr_t(p)) + 0x87823448; + dlfree(p); + } + int memhash() { + return hash; + } +} // namespace eng + +#endif // ifdef __linux__ + + diff --git a/luprex/core/cpp/eng-malloc.hpp b/luprex/core/cpp/eng-malloc.hpp new file mode 100644 index 00000000..a622139e --- /dev/null +++ b/luprex/core/cpp/eng-malloc.hpp @@ -0,0 +1,152 @@ +// +// eng-malloc +// +// The engine has its own private eng::malloc which it uses to allocate +// everything. The engine's malloc heap only contains engine data structures. +// This helps achieve determinism when playing a replay log. +// +// The engine's eng::malloc is a thin wrapper around Doug Lea's Malloc, a good +// general-purpose single-threaded malloc. It's probably not the fastest any +// more (it was, once), but it's still quite good. It's also fairly easy +// to work with. +// +// In order to get all engine data structures into the eng::malloc heap, you +// need to jump through quite a few hoops: +// +// * When using STL classes, you need to use the 'eng' variant of those classes: +// +// - eng::string instead of std::string (include "wrap-string.hpp") +// - eng::vector instead of std::vector (include "wrap-vector.hpp") +// - eng::map instead of std::map (include "wrap-map.hpp") +// - etc. +// +// These eng classes allocate memory using eng::malloc instead of malloc. +// +// * All your classes must derive from eng::opnew. This adds a custom operator +// new and operator delete to your class, which allocate using eng::malloc. +// +// * Use eng::make_shared and eng::make_unique instead of std::make_shared and +// std::make_unique. +// +// * Simple classes like std::pair, std::string_view, std::less, std::hash, and +// so forth don't allocate memory. Those classes are not wrapped. There is +// no eng::pair, eng::less, etc. +// +// * Be aware that most C++ streams use the system malloc heap, and there's no +// way to change that. Fortunately, eng::ostringstream uses the dlmalloc +// heap. +// +// * Failing to jump through all these hoops won't break your code in any +// obvious way - you'll just have some of your data structures in the malloc +// heap instead of the eng::malloc heap. This can break determinism of +// replay. +// +#ifndef ENG_MALLOC_HPP +#define ENG_MALLOC_HPP + +#include +#include + +namespace eng { +#ifdef __linux__ +void* malloc(size_t x); +void free(void *p); +void* realloc(void*, size_t); +int memhash(); +#else +inline void *malloc(size_t x) { return ::malloc(x); } +inline void free(void *p) { return ::free(x); } +inline void *realloc(void *p, size_t x) { return ::realloc(p, x); } +inline int memhash() { return 0; } +#endif +} // namespace eng + +// An allocator for lua states that uses eng::malloc and eng::free +namespace eng { + inline void *l_alloc(void *ud, void *ptr, size_t osize, size_t nsize) { + if (nsize == 0) { + ::eng::free(ptr); + return NULL; + } else { + return ::eng::realloc(ptr, nsize); + } + } +} // namespace eng + +// eng_allocator is similar to std::allocator, but allocates +// objects using eng::malloc and eng::free. +template +class eng_allocator +{ +public: + using value_type = T; + eng_allocator() noexcept {} + template eng_allocator(eng_allocator const&) noexcept {} + + value_type* allocate(std::size_t n) + { + return static_cast(eng::malloc(n*sizeof(value_type))); + } + + void deallocate(value_type* p, std::size_t) noexcept + { + eng::free(p); + } +}; + +// Another name for eng_allocator is eng::allocator. +namespace eng { + template + using allocator = ::eng_allocator; +} // namespace eng + +// Mandated equality and inequality operators for eng_allocator. +template +bool operator==(const eng_allocator &, const eng_allocator &) noexcept +{ + return true; +} +template +bool operator!=(const eng_allocator &, const eng_allocator &) noexcept +{ + return false; +} + +// eng::opnew. A class containing operator new and operator delete, +// meant to be used as a base class for inheritance. +namespace eng { + class opnew { + public: + void *operator new(size_t size) + { + return ::eng::malloc(size); + } + + void operator delete(void *p, size_t size) + { + return ::eng::free(p); + } + }; +} // namespace eng + +// eng::make_shared allocates shared objects using eng::malloc. +namespace eng { + template + inline ::std::shared_ptr make_shared(Args&&... args) { + static eng::allocator alloc; + return std::allocate_shared(alloc, args...); + } +} + +// eng::make_unique doesn't do anything different than std::make_unique: +// they both use operator new and delete. You must +// derive from eng::opnew to change operator new and delete. +namespace eng { + template + inline ::std::unique_ptr make_unique(Args&&... args) { + return std::make_unique(args...); + } +} // namespace eng + +#endif // ENG_MALLOC_HPP + diff --git a/luprex/core/cpp/eng-tests.cpp b/luprex/core/cpp/eng-tests.cpp index a423df4c..62a38b94 100644 --- a/luprex/core/cpp/eng-tests.cpp +++ b/luprex/core/cpp/eng-tests.cpp @@ -95,7 +95,7 @@ public: virtual void event_update() { double clock = get_clock(); if (clock > last_clock_ + 0.5) { - int ms = dlmalloc_hash(); + int ms = eng::memhash(); stdostream() << std::fixed << std::setprecision(2) << clock << " " << std::hex << ms << " "; count_++; last_clock_ = clock; diff --git a/luprex/core/cpp/lpxserver.cpp b/luprex/core/cpp/lpxserver.cpp index a5a426ac..0ef4e595 100644 --- a/luprex/core/cpp/lpxserver.cpp +++ b/luprex/core/cpp/lpxserver.cpp @@ -9,7 +9,7 @@ #include -class Client : public eng::heap { +class Client : public eng::opnew { public: int64_t actor_id_; SharedChannel channel_; diff --git a/luprex/core/cpp/luaconsole.cpp b/luprex/core/cpp/luaconsole.cpp index a4b44471..a1638b81 100644 --- a/luprex/core/cpp/luaconsole.cpp +++ b/luprex/core/cpp/luaconsole.cpp @@ -1,4 +1,4 @@ -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include "luastack.hpp" #include "wrap-string.hpp" #include "wrap-vector.hpp" @@ -10,7 +10,7 @@ #include LuaConsole::LuaConsole() { - lua_state_ = LuaStack::newstate(lalloc_dlmalloc); + lua_state_ = LuaStack::newstate(eng::l_alloc); clear_raw_input(); } diff --git a/luprex/core/cpp/luasnap.cpp b/luprex/core/cpp/luasnap.cpp index 98f3e5f5..beb39d59 100644 --- a/luprex/core/cpp/luasnap.cpp +++ b/luprex/core/cpp/luasnap.cpp @@ -10,7 +10,7 @@ LuaSnap::LuaSnap() { - state_ = LuaStack::newstate(lalloc_dlmalloc); + state_ = LuaStack::newstate(eng::l_alloc); LuaStack LS(state_); // Create the persist table and the unpersist table. diff --git a/luprex/core/cpp/luastack.cpp b/luprex/core/cpp/luastack.cpp index 9a621ac2..5a92b279 100644 --- a/luprex/core/cpp/luastack.cpp +++ b/luprex/core/cpp/luastack.cpp @@ -34,11 +34,21 @@ static int panicf(lua_State *L) { exit(1); } +// An allocator for lua states that uses system malloc and system free. +static void *l_alloc(void *ud, void *ptr, size_t osize, size_t nsize) { + if (nsize == 0) { + free(ptr); + return NULL; + } else { + return realloc(ptr, nsize); + } +} lua_State *LuaStack::newstate (lua_Alloc allocf) { - lua_State *L = lua_newstate(allocf, NULL); - if (L) lua_atpanic(L, &panicf); - return L; + if (allocf == nullptr) allocf = l_alloc; + lua_State *L = lua_newstate(allocf, NULL); + if (L) lua_atpanic(L, &panicf); + return L; } bool LuaStack::ckboolean(LuaSlot s) const { diff --git a/luprex/core/cpp/printbuffer.cpp b/luprex/core/cpp/printbuffer.cpp index 6b231741..79422361 100644 --- a/luprex/core/cpp/printbuffer.cpp +++ b/luprex/core/cpp/printbuffer.cpp @@ -5,7 +5,7 @@ #include #include -struct PrintBufferCore : public eng::heap { +struct PrintBufferCore : public eng::opnew { // The most recent lines printed. eng::deque lines_; diff --git a/luprex/core/cpp/printbuffer.hpp b/luprex/core/cpp/printbuffer.hpp index 06858fd6..a98849e2 100644 --- a/luprex/core/cpp/printbuffer.hpp +++ b/luprex/core/cpp/printbuffer.hpp @@ -89,7 +89,7 @@ struct PrintBufferCore; -class PrintBuffer : public eng::heap { +class PrintBuffer : public eng::opnew { private: PrintBufferCore *core_; @@ -138,7 +138,7 @@ public: }; -class PrintChanneler : public eng::heap { +class PrintChanneler : public eng::opnew { private: int64_t line_; public: diff --git a/luprex/core/cpp/source.cpp b/luprex/core/cpp/source.cpp index 800e3319..dcc4c882 100644 --- a/luprex/core/cpp/source.cpp +++ b/luprex/core/cpp/source.cpp @@ -498,7 +498,7 @@ void SourceDB::deserialize_source(util::LuaSourceVec *sv, StreamBuffer *sb) { // This function should not touch the dlmalloc heap. void SourceDB::register_lua_builtins() { - lua_State *L = LuaStack::newstate(lalloc_malloc); + lua_State *L = LuaStack::newstate(nullptr); luaL_openlibs(L); LuaVar globals,classtab,func; LuaStack LS(L, globals, classtab, func); diff --git a/luprex/core/cpp/streambuffer.cpp b/luprex/core/cpp/streambuffer.cpp index d8fdbb20..bda56942 100644 --- a/luprex/core/cpp/streambuffer.cpp +++ b/luprex/core/cpp/streambuffer.cpp @@ -1,6 +1,6 @@ #include "wrap-string.hpp" -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include "streambuffer.hpp" #include "spookyv2.hpp" @@ -25,7 +25,7 @@ StreamBuffer::StreamBuffer() { StreamBuffer::StreamBuffer(int64_t size, bool fixed) { assert(size >= 0); - init(fixed, true, (char*)dlmalloc(size), size); + init(fixed, true, (char*)eng::malloc(size), size); } StreamBuffer::StreamBuffer(const char *s, int64_t size) { @@ -40,7 +40,7 @@ StreamBuffer::StreamBuffer(const eng::string &src) { } StreamBuffer::~StreamBuffer() { - if (owned_ && (buf_lo_ != 0)) dlfree(buf_lo_); + if (owned_ && (buf_lo_ != 0)) eng::free(buf_lo_); } int64_t StreamBuffer::total_reads() const { @@ -87,9 +87,9 @@ void StreamBuffer::make_space_slow(int64_t bytes) { } else if (existing_size >= desired_size) { if (data_size > 0) memcpy(buf_lo_, read_cursor_, data_size); } else { - char *nbuf = (char *)dlmalloc(desired_size); + char *nbuf = (char *)eng::malloc(desired_size); if (data_size > 0) memcpy(nbuf, read_cursor_, data_size); - if (buf_lo_ != nullptr) dlfree(buf_lo_); + if (buf_lo_ != nullptr) eng::free(buf_lo_); buf_lo_ = nbuf; buf_hi_ = nbuf + desired_size; } @@ -116,7 +116,7 @@ char *StreamBuffer::get_overwrite(int64_t size, int64_t write_count_after) { void StreamBuffer::clear() { assert(owned_); if (!fixed_size_) { - if (buf_lo_ != nullptr) dlfree(buf_lo_); + if (buf_lo_ != nullptr) eng::free(buf_lo_); buf_lo_ = 0; buf_hi_ = 0; } diff --git a/luprex/core/cpp/two-mallocs.cpp b/luprex/core/cpp/two-mallocs.cpp deleted file mode 100644 index 67b88dfb..00000000 --- a/luprex/core/cpp/two-mallocs.cpp +++ /dev/null @@ -1,64 +0,0 @@ - -// We only use a custom allocator on linux (for now) -// The allocator we chose is 'dlmalloc' (doug lea's malloc). -// It's a good allocator for single-threaded programs. -// It needs to be configured by setting a bunch of defines. -// -#ifdef __linux__ - -// We need this to define dlmalloc, not malloc. -#define USE_DL_PREFIX 1 - -// We don't need mspaces. -#define ONLY_MSPACES 0 -#define MSPACES 0 - -// We don't need mallinfo -#define NO_MALLINFO 1 - -// We don't need dlmalloc_inspect_all -#define MALLOC_INSPECT_ALL 0 - -// We don't need dlmalloc_stats. -#define NO_MALLOC_STATS 1 - -// Disable locking. The entire engine is single-threaded. -#define USE_LOCKS 0 - -// For now, we'll let the allocator use mmap to get memory. -// It's not clear if this is going to be deterministic. -#define HAVE_MMAP 1 - -// One way to force determinism would be to emulate sbrk -// using mmap and mremap, always putting the heap at a fixed -// address. For now, we're not doing that, we're just -// using mmap and relying on that being deterministic (we hope). -#define HAVE_MORECORE 0 -#define MORECORE emulate_sbrk - -// The properties of mmap under linux -#define MMAP_CLEARS 1 -#define HAVE_MREMAP 1 - -// Don't generate random seeds, or time-based seeds. -#define USE_DEV_RANDOM 0 -#define LACKS_TIME_H 1 - -#include "dlmalloc/dlmalloc.c" - -#endif - -int dlmalloc_hash() { - void *blocks[15]; - int hash = 0; - for (int i = 0; i < 15; i++) { - void *blk = dlmalloc(1 << i); - blocks[i] = blk; - hash = (hash * 17) + (int)(intptr_t)(blk); - } - for (int i = 0; i < 15; i++) { - dlfree(blocks[i]); - } - return (hash & 0x7FFFFFFF) | (0x40000000); -} - diff --git a/luprex/core/cpp/two-mallocs.hpp b/luprex/core/cpp/two-mallocs.hpp deleted file mode 100644 index 70c3630a..00000000 --- a/luprex/core/cpp/two-mallocs.hpp +++ /dev/null @@ -1,157 +0,0 @@ -// -// Two Mallocs: -// -// The purpose of this file is to put all engine data structures into -// a private heap that isn't used by any other library. This helps -// achieve determinism when playing a replay log. -// -// For the engine's heap, we chose Doug Lea's Malloc (dlmalloc). It's -// a good general-purpose single-threaded malloc. It's probably not -// the fastest any more (it was, once), but it's still quite good. It -// may be possible to replace dlmalloc with another malloc, but -// dlmalloc is pretty easy to work with. -// -// In order to get all engine data structures into the dlmalloc heap, -// you need to jump through quite a few hoops: -// -// * When using STL classes, you need to use the 'eng' variant of those -// classes: -// -// use 'eng::string' instead of std::string (include "wrap-string.hpp") -// use 'eng::vector' instead of std::vector (include "wrap-vector.hpp") -// use 'eng::map' instead of std::map (include "wrap-map.hpp") -// etc. -// -// These eng classes allocate memory from dlmalloc instead of malloc. -// -// * All your classes must derive from eng::heap. This adds a custom -// operator new and operator delete to your class. -// -// * Use eng::make_shared and eng::make_unique instead of std::make_shared -// and std::make_unique. -// -// * Simple classes like std::pair, std::string_view, std::less, -// std::hash, and so forth don't allocate memory. Those classes -// are not wrapped. There is no eng::pair, eng:less, etc. -// -// * Be aware that most C++ streams use the malloc heap, and there's no -// way to change that. Fortunately, eng::ostringstream uses the -// dlmalloc heap. -// -// * Failing to jump through all these hoops won't break your code in -// any obvious way - you'll just have some of your data structures in -// the malloc heap instead of the dlmalloc heap. This can break -// determinism of replay. -// -#ifndef TWO_MALLOCS_HPP -#define TWO_MALLOCS_HPP - -#include -#include - -// dlmalloc is only used on linux. -extern "C" { -#ifdef __linux__ -void* dlmalloc(size_t x); -void dlfree(void *p); -void* dlrealloc(void*, size_t); -#else -void* dlmalloc(size_t x) { return malloc(x); } -void dlfree(void *p) { free(p); } -void* dlrealloc(void *p, size_t x) { return realloc(p,x); } -#endif -} - -// Return the current state of the dlmalloc allocator as a 30-bit hash. -extern int dlmalloc_hash(); - -// An allocator for lua states that uses dlmalloc and dlfree. -inline void *lalloc_dlmalloc (void *ud, void *ptr, size_t osize, size_t nsize) { - if (nsize == 0) { - dlfree(ptr); - return NULL; - } else { - return dlrealloc(ptr, nsize); - } -} - -// An allocator for lua states that uses malloc and free. -inline void *lalloc_malloc (void *ud, void *ptr, size_t osize, size_t nsize) { - if (nsize == 0) { - free(ptr); - return NULL; - } else { - return realloc(ptr, nsize); - } -} - -// eng:allocator: a class meant to be used as an STL Allocator. -// Causes objects to be allocated using dlmalloc and dlfree. -template -class dlmalloc_allocator -{ -public: - using value_type = T; - dlmalloc_allocator() noexcept {} - template dlmalloc_allocator(dlmalloc_allocator const&) noexcept {} - - value_type* allocate(std::size_t n) - { - return static_cast(dlmalloc(n*sizeof(value_type))); - } - - void deallocate(value_type* p, std::size_t) noexcept - { - dlfree(p); - } -}; - -template -bool operator==(const dlmalloc_allocator &, const dlmalloc_allocator &) noexcept -{ - return true; -} -template -bool operator!=(const dlmalloc_allocator &, const dlmalloc_allocator &) noexcept -{ - return false; -} - -// Another name for dlmalloc_allocator -namespace eng { - template - using allocator = dlmalloc_allocator; -} - -// eng::heap a class meant to be used as a base class. -// Causes 'new' and 'delete' for this class to use dlmalloc and dlfree. -namespace eng { - class heap { - public: - void *operator new(size_t size) - { - return dlmalloc(size); - } - - void operator delete(void *p, size_t size) - { - return dlfree(p); - } - }; -} // namespace - -// eng::make_shared allocates shared objects in the dlmalloc heap. -namespace eng { - template - inline std::shared_ptr make_shared(Args&&... args) { - static eng::allocator alloc; - return std::allocate_shared(alloc, args...); - } - template - inline std::unique_ptr make_unique(Args&&... args) { - return std::make_unique(args...); - } -} // namespace eng - -#endif // TWO_MALLOCS_HPP - diff --git a/luprex/core/wrap/mkstub.py b/luprex/core/wrap/mkstub.py index df2c64eb..568aa722 100755 --- a/luprex/core/wrap/mkstub.py +++ b/luprex/core/wrap/mkstub.py @@ -10,7 +10,7 @@ with open(f"wrap-{dash}.hpp", "w") as f: print(f"#ifndef WRAP_{ubase}_HPP", file=f) print(f"#define WRAP_{ubase}_HPP", file=f) print("", file=f) - print('#include "two-mallocs.hpp"', file=f) + print('#include "eng-malloc.hpp"', file=f) print(f"#include <{base}>", file=f) print("", file=f) print("namespace eng {", file=f) diff --git a/luprex/core/wrap/wrap-deque.hpp b/luprex/core/wrap/wrap-deque.hpp index 9e6fc9e7..238fc0dd 100644 --- a/luprex/core/wrap/wrap-deque.hpp +++ b/luprex/core/wrap/wrap-deque.hpp @@ -1,7 +1,7 @@ #ifndef WRAP_DEQUE_HPP #define WRAP_DEQUE_HPP -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include namespace eng { diff --git a/luprex/core/wrap/wrap-map.hpp b/luprex/core/wrap/wrap-map.hpp index 3d017e95..10905294 100644 --- a/luprex/core/wrap/wrap-map.hpp +++ b/luprex/core/wrap/wrap-map.hpp @@ -1,7 +1,7 @@ #ifndef WRAP_MAP_HPP #define WRAP_MAP_HPP -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include namespace eng { diff --git a/luprex/core/wrap/wrap-set.hpp b/luprex/core/wrap/wrap-set.hpp index adde1cb4..8beee51d 100644 --- a/luprex/core/wrap/wrap-set.hpp +++ b/luprex/core/wrap/wrap-set.hpp @@ -1,7 +1,7 @@ #ifndef WRAP_SET_HPP #define WRAP_SET_HPP -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include namespace eng { diff --git a/luprex/core/wrap/wrap-sstream.hpp b/luprex/core/wrap/wrap-sstream.hpp index f733ec4d..60ed91b5 100644 --- a/luprex/core/wrap/wrap-sstream.hpp +++ b/luprex/core/wrap/wrap-sstream.hpp @@ -1,7 +1,7 @@ #ifndef WRAP_SSTREAM_HPP #define WRAP_SSTREAM_HPP -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include namespace eng { diff --git a/luprex/core/wrap/wrap-string.hpp b/luprex/core/wrap/wrap-string.hpp index 2819b752..df54cc62 100644 --- a/luprex/core/wrap/wrap-string.hpp +++ b/luprex/core/wrap/wrap-string.hpp @@ -1,7 +1,7 @@ #ifndef WRAP_STRING_HPP #define WRAP_STRING_HPP -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include namespace eng { diff --git a/luprex/core/wrap/wrap-unordered-map.hpp b/luprex/core/wrap/wrap-unordered-map.hpp index f9edc5ff..0a3ecd23 100644 --- a/luprex/core/wrap/wrap-unordered-map.hpp +++ b/luprex/core/wrap/wrap-unordered-map.hpp @@ -1,7 +1,7 @@ #ifndef WRAP_UNORDERED_MAP_HPP #define WRAP_UNORDERED_MAP_HPP -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include namespace eng { diff --git a/luprex/core/wrap/wrap-unordered-set.hpp b/luprex/core/wrap/wrap-unordered-set.hpp index 58e3d88e..8854b006 100644 --- a/luprex/core/wrap/wrap-unordered-set.hpp +++ b/luprex/core/wrap/wrap-unordered-set.hpp @@ -1,7 +1,7 @@ #ifndef WRAP_UNORDERED_SET_HPP #define WRAP_UNORDERED_SET_HPP -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include namespace eng { diff --git a/luprex/core/wrap/wrap-vector.hpp b/luprex/core/wrap/wrap-vector.hpp index 077b1790..a9cb254b 100644 --- a/luprex/core/wrap/wrap-vector.hpp +++ b/luprex/core/wrap/wrap-vector.hpp @@ -1,7 +1,7 @@ #ifndef WRAP_VECTOR_HPP #define WRAP_VECTOR_HPP -#include "two-mallocs.hpp" +#include "eng-malloc.hpp" #include namespace eng { diff --git a/luprex/linuxlib/dlmalloc/dlmalloc.c b/luprex/linuxlib/dlmalloc/dlmalloc.c index b7f54b70..4fc64718 100644 --- a/luprex/linuxlib/dlmalloc/dlmalloc.c +++ b/luprex/linuxlib/dlmalloc/dlmalloc.c @@ -4286,10 +4286,9 @@ static int sys_trim(mstate m, size_t pad) { if (HAVE_MMAP && sp->size >= extra && !has_segment_link(m, sp)) { /* can't shrink if pinned */ - size_t newsize = sp->size - extra; /* Prefer mremap, fall back to munmap */ - if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) || - (CALL_MUNMAP(sp->base + newsize, extra) == 0)) { + if ((CALL_MREMAP(sp->base, sp->size, (sp->size - extra), 0) != MFAIL) || + (CALL_MUNMAP(sp->base + (sp->size - extra), extra) == 0)) { released = extra; } }