diff --git a/src/input/AsyncInputStream.cxx b/src/input/AsyncInputStream.cxx index ecccf9f65..1792eb540 100644 --- a/src/input/AsyncInputStream.cxx +++ b/src/input/AsyncInputStream.cxx @@ -38,7 +38,10 @@ AsyncInputStream::AsyncInputStream(EventLoop &event_loop, const char *_url, deferred_seek(event_loop, BIND_THIS_METHOD(DeferredSeek)), allocation(_buffer_size), buffer((uint8_t *)allocation.get(), _buffer_size), - resume_at(_resume_at) {} + resume_at(_resume_at) +{ + allocation.ForkCow(false); +} AsyncInputStream::~AsyncInputStream() { diff --git a/src/input/ThreadInputStream.cxx b/src/input/ThreadInputStream.cxx index 88251a70a..b9c9587a4 100644 --- a/src/input/ThreadInputStream.cxx +++ b/src/input/ThreadInputStream.cxx @@ -53,6 +53,8 @@ ThreadInputStream::Start() void *p = HugeAllocate(buffer_size); assert(p != nullptr); + HugeForkCow(p, buffer_size, false); + buffer = new CircularBuffer((uint8_t *)p, buffer_size); thread.Start(); } diff --git a/src/util/HugeAllocator.cxx b/src/util/HugeAllocator.cxx index 5116a5923..6fcdad953 100644 --- a/src/util/HugeAllocator.cxx +++ b/src/util/HugeAllocator.cxx @@ -73,12 +73,6 @@ HugeAllocate(size_t size) madvise(p, size, MADV_HUGEPAGE); #endif -#ifdef MADV_DONTFORK - /* just in case MPD needs to fork, don't copy this allocation - to the child process, to reduce overhead */ - madvise(p, size, MADV_DONTFORK); -#endif - return p; } @@ -88,6 +82,15 @@ HugeFree(void *p, size_t size) noexcept munmap(p, AlignToPageSize(size)); } +void +HugeForkCow(void *p, size_t size, bool enable) noexcept +{ +#ifdef MADV_DONTFORK + madvise(p, AlignToPageSize(size), + enable ? MADV_DOFORK : MADV_DONTFORK); +#endif +} + void HugeDiscard(void *p, size_t size) noexcept { diff --git a/src/util/HugeAllocator.hxx b/src/util/HugeAllocator.hxx index 46b65e29a..421cf7da4 100644 --- a/src/util/HugeAllocator.hxx +++ b/src/util/HugeAllocator.hxx @@ -56,6 +56,13 @@ HugeAllocate(size_t size); void HugeFree(void *p, size_t size) noexcept; +/** + * Control whether this allocation is copied to newly forked child + * processes. Disabling that makes forking a little bit cheaper. + */ +void +HugeForkCow(void *p, size_t size, bool enable) noexcept; + /** * Discard any data stored in the allocation and give the memory back * to the kernel. After returning, the allocation still exists and @@ -80,6 +87,11 @@ HugeFree(void *p, gcc_unused size_t size) noexcept VirtualFree(p, 0, MEM_RELEASE); } +static inline void +HugeForkCow(void *, size_t, bool) noexcept +{ +} + static inline void HugeDiscard(void *p, size_t size) noexcept { @@ -106,6 +118,11 @@ HugeFree(void *_p, size_t) noexcept delete[] p; } +static inline void +HugeForkCow(void *, size_t, bool) noexcept +{ +} + static inline void HugeDiscard(void *, size_t) noexcept { @@ -140,6 +157,10 @@ public: return *this; } + void ForkCow(bool enable) noexcept { + HugeForkCow(data, size, enable); + } + void Discard() noexcept { HugeDiscard(data, size); } diff --git a/src/util/SliceBuffer.hxx b/src/util/SliceBuffer.hxx index a623ab7a6..de553fcb4 100644 --- a/src/util/SliceBuffer.hxx +++ b/src/util/SliceBuffer.hxx @@ -74,6 +74,8 @@ public: :n_max(_count), data((Slice *)HugeAllocate(CalcAllocationSize())) { assert(n_max > 0); + + HugeForkCow(data, CalcAllocationSize(), false); } ~SliceBuffer() {