diff --git a/src/input/ThreadInputStream.cxx b/src/input/ThreadInputStream.cxx index b9c9587a4..36f77d557 100644 --- a/src/input/ThreadInputStream.cxx +++ b/src/input/ThreadInputStream.cxx @@ -50,12 +50,13 @@ ThreadInputStream::Start() { assert(buffer == nullptr); - void *p = HugeAllocate(buffer_size); - assert(p != nullptr); + auto allocation = HugeAllocate(buffer_size); + assert(allocation != nullptr); - HugeForkCow(p, buffer_size, false); + HugeForkCow(allocation.data, allocation.size, false); - buffer = new CircularBuffer((uint8_t *)p, buffer_size); + buffer = new CircularBuffer((uint8_t *)allocation.data, + allocation.size); thread.Start(); } diff --git a/src/util/HugeAllocator.cxx b/src/util/HugeAllocator.cxx index 6fcdad953..f5d4683be 100644 --- a/src/util/HugeAllocator.cxx +++ b/src/util/HugeAllocator.cxx @@ -55,7 +55,7 @@ AlignToPageSize(size_t size) noexcept return (size + ps - 1) / ps * ps; } -void * +WritableBuffer HugeAllocate(size_t size) { size = AlignToPageSize(size); @@ -73,7 +73,7 @@ HugeAllocate(size_t size) madvise(p, size, MADV_HUGEPAGE); #endif - return p; + return {p, size}; } void @@ -101,7 +101,7 @@ HugeDiscard(void *p, size_t size) noexcept #elif defined(WIN32) -void * +WritableBuffer HugeAllocate(size_t size) { // TODO: use MEM_LARGE_PAGES @@ -111,7 +111,8 @@ HugeAllocate(size_t size) if (p == nullptr) throw std::bad_alloc(); - return p; + // TODO: round size up to the page size + return {p, size}; } #endif diff --git a/src/util/HugeAllocator.hxx b/src/util/HugeAllocator.hxx index 421cf7da4..765b4fc6b 100644 --- a/src/util/HugeAllocator.hxx +++ b/src/util/HugeAllocator.hxx @@ -30,6 +30,7 @@ #ifndef HUGE_ALLOCATOR_HXX #define HUGE_ALLOCATOR_HXX +#include "WritableBuffer.hxx" #include "Compiler.h" #include @@ -44,9 +45,12 @@ * need it anymore. On the downside, this call is expensive. * * Throws std::bad_alloc on error + * + * @returns the allocated buffer with a size which may be rounded up + * (to the next page size), so callers can take advantage of this + * allocation overhead */ -gcc_malloc -void * +WritableBuffer HugeAllocate(size_t size); /** @@ -77,8 +81,7 @@ HugeDiscard(void *p, size_t size) noexcept; #elif defined(WIN32) #include -gcc_malloc -void * +WritableBuffer HugeAllocate(size_t size); static inline void @@ -104,11 +107,10 @@ HugeDiscard(void *p, size_t size) noexcept #include -gcc_malloc -static inline void * +WritableBuffer HugeAllocate(size_t size) { - return new uint8_t[size]; + return {new uint8_t[size], size}; } static inline void @@ -134,46 +136,44 @@ HugeDiscard(void *, size_t) noexcept * Automatic huge memory allocation management. */ class HugeAllocation { - void *data = nullptr; - size_t size; + WritableBuffer buffer = nullptr; public: HugeAllocation() = default; explicit HugeAllocation(size_t _size) - :data(HugeAllocate(_size)), size(_size) {} + :buffer(HugeAllocate(_size)) {} HugeAllocation(HugeAllocation &&src) noexcept - :data(std::exchange(src.data, nullptr)), size(src.size) {} + :buffer(std::exchange(src.buffer, nullptr)) {} ~HugeAllocation() { - if (data != nullptr) - HugeFree(data, size); + if (buffer != nullptr) + HugeFree(buffer.data, buffer.size); } HugeAllocation &operator=(HugeAllocation &&src) noexcept { - std::swap(data, src.data); - std::swap(size, src.size); + std::swap(buffer, src.buffer); return *this; } void ForkCow(bool enable) noexcept { - HugeForkCow(data, size, enable); + HugeForkCow(buffer.data, buffer.size, enable); } void Discard() noexcept { - HugeDiscard(data, size); + HugeDiscard(buffer.data, buffer.size); } void reset() noexcept { - if (data != nullptr) { - HugeFree(data, size); - data = nullptr; + if (buffer != nullptr) { + HugeFree(buffer.data, buffer.size); + buffer = nullptr; } } void *get() noexcept { - return data; + return buffer.data; } }; diff --git a/src/util/SliceBuffer.hxx b/src/util/SliceBuffer.hxx index de553fcb4..76e5d3b83 100644 --- a/src/util/SliceBuffer.hxx +++ b/src/util/SliceBuffer.hxx @@ -72,7 +72,7 @@ class SliceBuffer { public: SliceBuffer(unsigned _count) :n_max(_count), - data((Slice *)HugeAllocate(CalcAllocationSize())) { + data((Slice *)HugeAllocate(CalcAllocationSize()).data) { assert(n_max > 0); HugeForkCow(data, CalcAllocationSize(), false);