Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ ver 0.25 (not yet released)
* require Meson 1.2

ver 0.24.9 (not yet released)
* database
- upnp: refuse to build with libupnp >= 1.14.26 due to API breakage

ver 0.24.8 (2026/01/26)
* input
Expand Down
2 changes: 2 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,7 @@ subdir('src/system')
subdir('src/system/linux')
subdir('src/thread')
subdir('src/net')
subdir('src/memory')
subdir('src/event')
subdir('src/win32')

Expand Down Expand Up @@ -642,6 +643,7 @@ mpd = build_target(
zeroconf_dep,
more_deps,
chromaprint_dep,
memory_dep,
fmt_dep,
],
link_args: link_args,
Expand Down
2 changes: 1 addition & 1 deletion python/build/libs.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
'--without-portaudio', '--without-portaudiocpp', '--without-sndfile',
'--without-flac',
],
base='libopenmpt-0.8.3+release.autotools',
base='libopenmpt-0.8.4+release.autotools',
)

wildmidi = CmakeProject(
Expand Down
2 changes: 1 addition & 1 deletion src/MusicBuffer.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

#include "MusicChunk.hxx"
#include "MusicChunkPtr.hxx"
#include "util/SliceBuffer.hxx"
#include "memory/SliceBuffer.hxx"
#include "thread/Mutex.hxx"

/**
Expand Down
2 changes: 1 addition & 1 deletion src/input/AsyncInputStream.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include "InputStream.hxx"
#include "thread/Cond.hxx"
#include "event/InjectEvent.hxx"
#include "util/HugeAllocator.hxx"
#include "memory/HugeArray.hxx"
#include "util/CircularBuffer.hxx"

#include <cstddef>
Expand Down
2 changes: 1 addition & 1 deletion src/input/BufferingInputStream.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include "thread/Thread.hxx"
#include "thread/Mutex.hxx"
#include "thread/Cond.hxx"
#include "util/SparseBuffer.hxx"
#include "memory/SparseBuffer.hxx"

#include <cstddef>
#include <exception>
Expand Down
2 changes: 1 addition & 1 deletion src/input/ThreadInputStream.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include "InputStream.hxx"
#include "thread/Thread.hxx"
#include "thread/Cond.hxx"
#include "util/HugeAllocator.hxx"
#include "memory/HugeArray.hxx"
#include "util/CircularBuffer.hxx"

#include <cassert>
Expand Down
2 changes: 2 additions & 0 deletions src/input/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ input_basic = static_library(
input_api_dep,
thread_dep,
event_dep,
memory_dep,
],
)

Expand All @@ -42,6 +43,7 @@ input_basic_dep = declare_dependency(
input_api_dep,
thread_dep,
event_dep,
memory_dep,
],
)

Expand Down
11 changes: 11 additions & 0 deletions src/lib/upnp/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,23 @@ endif

if upnp_option == 'auto'
upnp_dep = dependency('libupnp', version: '>= 1.8', required: false)

if upnp_dep.found() and upnp_dep.version().version_compare('>= 1.14.26')
warning('Your libupnp version is known to be broken, see https://github.com/pupnp/pupnp/issues/528 - disabling')
upnp_dep = dependency('', required: false)
endif

conf.set('USING_PUPNP', upnp_dep.found())
if not upnp_dep.found()
upnp_dep = dependency('libnpupnp', version: '>= 1.8', required: false)
endif
elif upnp_option == 'pupnp'
upnp_dep = dependency('libupnp', version: '>= 1.8', required: true)

if upnp_dep.found() and upnp_dep.version().version_compare('>= 1.14.26')
error('Your libupnp version is known to be broken, see https://github.com/pupnp/pupnp/issues/528')
endif

conf.set('USING_PUPNP', true)
elif upnp_option == 'npupnp'
upnp_dep = dependency('libnpupnp', required: true)
Expand Down
68 changes: 68 additions & 0 deletions src/memory/HugeAllocator.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: BSD-2-Clause
// author: Max Kellermann <max.kellermann@gmail.com>

#include "HugeAllocator.hxx"

#ifdef __linux__

#include "system/PageAllocator.hxx"
#include "system/PageSize.hxx"
#include "system/VmaName.hxx"

static std::span<std::byte>
AlignToPageSize(std::span<std::byte> p) noexcept
{
return {p.data(), AlignToPageSize(p.size())};
}

std::span<std::byte>
HugeAllocate(size_t size)
{
size = AlignToPageSize(size);

const std::span<std::byte> p{AllocatePages(size), size};
EnableHugePages(p);
return p;
}

void
HugeFree(std::span<std::byte> p) noexcept
{
FreePages(AlignToPageSize(p));
}

void
HugeSetName(std::span<std::byte> p, const char *name) noexcept
{
SetVmaName(p.data(), p.size(), name);
}

void
HugeForkCow(std::span<std::byte> p, bool enable) noexcept
{
EnablePageFork(AlignToPageSize(p), enable);
}

void
HugeDiscard(std::span<std::byte> p) noexcept
{
DiscardPages(AlignToPageSize(p));
}

#elif defined(_WIN32)

std::span<std::byte>
HugeAllocate(size_t size)
{
// TODO: use MEM_LARGE_PAGES
void *p = VirtualAlloc(nullptr, size,
MEM_COMMIT|MEM_RESERVE,
PAGE_READWRITE);
if (p == nullptr)
throw std::bad_alloc();

// TODO: round size up to the page size
return {(std::byte *)p, size};
}

#endif
117 changes: 117 additions & 0 deletions src/memory/HugeAllocator.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// SPDX-License-Identifier: BSD-2-Clause
// author: Max Kellermann <max.kellermann@gmail.com>

#pragma once

#include <cstddef>
#include <span>

#ifdef __linux__

/**
* Allocate a huge amount of memory. This will be done in a way that
* allows giving the memory back to the kernel as soon as we don't
* 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
*/
std::span<std::byte>
HugeAllocate(size_t size);

/**
* @param p an allocation returned by HugeAllocate()
*/
void
HugeFree(std::span<std::byte> p) noexcept;

/**
* Set a name for the specified virtual memory area.
*
* This feature requires Linux 5.17.
*/
void
HugeSetName(std::span<std::byte> p, const char *name) noexcept;

/**
* Control whether this allocation is copied to newly forked child
* processes. Disabling that makes forking a little bit cheaper.
*/
void
HugeForkCow(std::span<std::byte> p, 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
* can be reused at any time, but its contents are undefined.
*
* @param p an allocation returned by HugeAllocate()
*/
void
HugeDiscard(std::span<std::byte> p) noexcept;

#elif defined(_WIN32)
#include <memoryapi.h>

std::span<std::byte>
HugeAllocate(size_t size);

static inline void
HugeFree(std::span<std::byte> p) noexcept
{
VirtualFree(p.data(), 0, MEM_RELEASE);
}

static inline void
HugeSetName(std::span<std::byte>, const char *) noexcept
{
}

static inline void
HugeForkCow(std::span<std::byte>, bool) noexcept
{
}

static inline void
HugeDiscard(std::span<std::byte> p) noexcept
{
VirtualAlloc(p.data(), p.size(), MEM_RESET, PAGE_NOACCESS);
}

#else

/* not Linux: fall back to standard C calls */

#include <cstdint>

static inline std::span<std::byte>
HugeAllocate(size_t size)
{
return {new std::byte[size], size};
}

static inline void
HugeFree(std::span<std::byte> p) noexcept
{
delete[] p.data();
}

static inline void
HugeSetName(std::span<std::byte>, const char *) noexcept
{
}

static inline void
HugeForkCow(std::span<std::byte>, bool) noexcept
{
}

static inline void
HugeDiscard(std::span<std::byte>) noexcept
{
}

#endif
Loading
Loading