aboutsummaryrefslogtreecommitdiffstats
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/util/HugeAllocator.cxx87
-rw-r--r--src/util/HugeAllocator.hxx82
-rw-r--r--src/util/LazyRandomEngine.cxx31
-rw-r--r--src/util/LazyRandomEngine.hxx67
-rw-r--r--src/util/Manual.hxx111
-rw-r--r--src/util/PeakBuffer.cxx143
-rw-r--r--src/util/PeakBuffer.hxx66
-rw-r--r--src/util/RefCount.hxx59
-rw-r--r--src/util/SliceBuffer.hxx161
-rw-r--r--src/util/bit_reverse.h5
-rw-r--r--src/util/fifo_buffer.c218
-rw-r--r--src/util/fifo_buffer.h164
-rw-r--r--src/util/growing_fifo.c (renamed from src/growing_fifo.c)0
-rw-r--r--src/util/growing_fifo.h (renamed from src/growing_fifo.h)0
-rw-r--r--src/util/list.h53
-rw-r--r--src/utils.c1
-rw-r--r--src/utils.h12
17 files changed, 1219 insertions, 41 deletions
diff --git a/src/util/HugeAllocator.cxx b/src/util/HugeAllocator.cxx
new file mode 100644
index 000000000..d1c55c965
--- /dev/null
+++ b/src/util/HugeAllocator.cxx
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "HugeAllocator.hxx"
+
+#ifdef __linux__
+#include <sys/mman.h>
+#include <unistd.h>
+#else
+#include <stdlib.h>
+#endif
+
+#ifdef __linux__
+
+/**
+ * Round up the parameter, make it page-aligned.
+ */
+gcc_const
+static size_t
+AlignToPageSize(size_t size)
+{
+ static const long page_size = sysconf(_SC_PAGESIZE);
+ if (page_size > 0)
+ return size;
+
+ size_t ps(page_size);
+ return (size + ps - 1) / ps * ps;
+}
+
+void *
+HugeAllocate(size_t size)
+{
+ size = AlignToPageSize(size);
+
+ constexpr int flags = MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE;
+ void *p = mmap(nullptr, size,
+ PROT_READ|PROT_WRITE, flags,
+ -1, 0);
+ if (p == (void *)-1)
+ return nullptr;
+
+#ifdef MADV_HUGEPAGE
+ /* allow the Linux kernel to use "Huge Pages", which reduces page
+ table overhead for this big chunk of data */
+ 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;
+}
+
+void
+HugeFree(void *p, size_t size)
+{
+ munmap(p, AlignToPageSize(size));
+}
+
+void
+HugeDiscard(void *p, size_t size)
+{
+#ifdef MADV_DONTNEED
+ madvise(p, AlignToPageSize(size), MADV_DONTNEED);
+#endif
+}
+
+#endif
diff --git a/src/util/HugeAllocator.hxx b/src/util/HugeAllocator.hxx
new file mode 100644
index 000000000..01c92cd43
--- /dev/null
+++ b/src/util/HugeAllocator.hxx
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_HUGE_ALLOCATOR_HXX
+#define MPD_HUGE_ALLOCATOR_HXX
+
+#include "gcc.h"
+
+#include <stddef.h>
+
+#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.
+ */
+gcc_malloc
+void *
+HugeAllocate(size_t size);
+
+/**
+ * @param p an allocation returned by HugeAllocate()
+ * @param size the allocation's size as passed to HugeAllocate()
+ */
+void
+HugeFree(void *p, size_t size);
+
+/**
+ * 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()
+ * @param size the allocation's size as passed to HugeAllocate()
+ */
+void
+HugeDiscard(void *p, size_t size);
+
+#else
+
+/* not Linux: fall back to standard C calls */
+
+#include <stdlib.h>
+
+gcc_malloc
+static inline void *
+HugeAllocate(size_t size)
+{
+ return malloc(size);
+}
+
+static inline void
+HugeFree(void *p, size_t)
+{
+ free(p);
+}
+
+static inline void
+HugeDiscard(void *, size_t)
+{
+}
+
+#endif
+
+#endif
diff --git a/src/util/LazyRandomEngine.cxx b/src/util/LazyRandomEngine.cxx
new file mode 100644
index 000000000..0f90ebb2e
--- /dev/null
+++ b/src/util/LazyRandomEngine.cxx
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "LazyRandomEngine.hxx"
+
+void
+LazyRandomEngine::AutoCreate()
+{
+ if (engine != nullptr)
+ return;
+
+ std::random_device rd;
+ engine = new std::mt19937(rd());
+}
diff --git a/src/util/LazyRandomEngine.hxx b/src/util/LazyRandomEngine.hxx
new file mode 100644
index 000000000..8afe1d1c0
--- /dev/null
+++ b/src/util/LazyRandomEngine.hxx
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_LAZY_RANDOM_ENGINE_HXX
+#define MPD_LAZY_RANDOM_ENGINE_HXX
+
+#include "check.h"
+
+#include <random>
+
+#include <assert.h>
+
+/**
+ * A random engine that will be created and seeded on demand.
+ */
+class LazyRandomEngine {
+ std::mt19937 *engine;
+
+public:
+ typedef std::mt19937::result_type result_type;
+
+ LazyRandomEngine():engine(nullptr) {}
+ ~LazyRandomEngine() {
+ delete engine;
+ }
+
+ LazyRandomEngine(const LazyRandomEngine &other) = delete;
+ LazyRandomEngine &operator=(const LazyRandomEngine &other) = delete;
+
+ /**
+ * Create and seed the real engine. Call this before any
+ * other method.
+ */
+ void AutoCreate();
+
+ result_type min() const {
+ return engine->min();
+ }
+
+ result_type max() const {
+ return engine->max();
+ }
+
+ result_type operator()() {
+ assert(engine != nullptr);
+
+ return engine->operator()();
+ }
+};
+
+#endif
diff --git a/src/util/Manual.hxx b/src/util/Manual.hxx
new file mode 100644
index 000000000..ecd2c52b8
--- /dev/null
+++ b/src/util/Manual.hxx
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2013 Max Kellermann <max@duempel.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MPD_MANUAL_HXX
+#define MPD_MANUAL_HXX
+
+#include "gcc.h"
+
+#include <new>
+
+#if !defined(__clang__) && __GNUC__ && !GCC_CHECK_VERSION(4,8)
+#include <type_traits>
+#endif
+
+#include <assert.h>
+
+/**
+ * Container for an object that gets constructed and destructed
+ * manually. The object is constructed in-place, and therefore
+ * without allocation overhead. It can be constructed and destructed
+ * repeatedly.
+ */
+template<class T>
+class Manual {
+#if !defined(__clang__) && __GNUC__ && !GCC_CHECK_VERSION(4,8)
+ /* no alignas() on gcc < 4.8: apply worst-case fallback */
+ __attribute__((aligned(8)))
+#else
+ alignas(T)
+#endif
+ char data[sizeof(T)];
+
+#ifndef NDEBUG
+ bool initialized;
+#endif
+
+public:
+#ifndef NDEBUG
+ Manual():initialized(false) {}
+ ~Manual() {
+ assert(!initialized);
+ }
+#endif
+
+ template<typename... Args>
+ void Construct(Args&&... args) {
+ assert(!initialized);
+
+ void *p = data;
+ new(p) T(std::forward<Args>(args)...);
+
+#ifndef NDEBUG
+ initialized = true;
+#endif
+ }
+
+ void Destruct() {
+ assert(initialized);
+
+ T *t = (T *)data;
+ t->T::~T();
+
+#ifndef NDEBUG
+ initialized = false;
+#endif
+ }
+
+ operator T &() {
+ return *(T *)data;
+ }
+
+ operator const T &() const {
+ return *(const T *)data;
+ }
+
+ T *operator->() {
+ return (T *)data;
+ }
+
+ const T *operator->() const {
+ return (T *)data;
+ }
+};
+
+#endif
diff --git a/src/util/PeakBuffer.cxx b/src/util/PeakBuffer.cxx
new file mode 100644
index 000000000..a3659b8f4
--- /dev/null
+++ b/src/util/PeakBuffer.cxx
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "PeakBuffer.hxx"
+#include "HugeAllocator.hxx"
+#include "fifo_buffer.h"
+
+#include <algorithm>
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+PeakBuffer::~PeakBuffer()
+{
+ if (normal_buffer != nullptr)
+ fifo_buffer_free(normal_buffer);
+
+ if (peak_buffer != nullptr)
+ HugeFree(peak_buffer, peak_size);
+}
+
+bool
+PeakBuffer::IsEmpty() const
+{
+ return (normal_buffer == nullptr ||
+ fifo_buffer_is_empty(normal_buffer)) &&
+ (peak_buffer == nullptr ||
+ fifo_buffer_is_empty(peak_buffer));
+}
+
+const void *
+PeakBuffer::Read(size_t *length_r) const
+{
+ if (normal_buffer != nullptr) {
+ const void *p = fifo_buffer_read(normal_buffer, length_r);
+ if (p != nullptr)
+ return p;
+ }
+
+ if (peak_buffer != nullptr) {
+ const void *p = fifo_buffer_read(peak_buffer, length_r);
+ if (p != nullptr)
+ return p;
+ }
+
+ return nullptr;
+}
+
+void
+PeakBuffer::Consume(size_t length)
+{
+ if (normal_buffer != nullptr && !fifo_buffer_is_empty(normal_buffer)) {
+ fifo_buffer_consume(normal_buffer, length);
+ return;
+ }
+
+ if (peak_buffer != nullptr && !fifo_buffer_is_empty(peak_buffer)) {
+ fifo_buffer_consume(peak_buffer, length);
+ if (fifo_buffer_is_empty(peak_buffer)) {
+ HugeFree(peak_buffer, peak_size);
+ peak_buffer = nullptr;
+ }
+
+ return;
+ }
+}
+
+static size_t
+AppendTo(fifo_buffer *buffer, const void *data, size_t length)
+{
+ assert(data != nullptr);
+ assert(length > 0);
+
+ size_t total = 0;
+
+ do {
+ size_t max_length;
+ void *p = fifo_buffer_write(buffer, &max_length);
+ if (p == nullptr)
+ break;
+
+ const size_t nbytes = std::min(length, max_length);
+ memcpy(p, data, nbytes);
+ fifo_buffer_append(buffer, nbytes);
+
+ data = (const uint8_t *)data + nbytes;
+ length -= nbytes;
+ total += nbytes;
+ } while (length > 0);
+
+ return total;
+}
+
+bool
+PeakBuffer::Append(const void *data, size_t length)
+{
+ if (length == 0)
+ return true;
+
+ if (peak_buffer != nullptr && !fifo_buffer_is_empty(peak_buffer)) {
+ size_t nbytes = AppendTo(peak_buffer, data, length);
+ return nbytes == length;
+ }
+
+ if (normal_buffer == nullptr)
+ normal_buffer = fifo_buffer_new(normal_size);
+
+ size_t nbytes = AppendTo(normal_buffer, data, length);
+ if (nbytes > 0) {
+ data = (const uint8_t *)data + nbytes;
+ length -= nbytes;
+ if (length == 0)
+ return true;
+ }
+
+ if (peak_buffer == nullptr && peak_size > 0) {
+ peak_buffer = (fifo_buffer *)HugeAllocate(peak_size);
+ if (peak_buffer == nullptr)
+ return false;
+
+ fifo_buffer_init(peak_buffer, peak_size);
+ }
+
+ nbytes = AppendTo(peak_buffer, data, length);
+ return nbytes == length;
+}
diff --git a/src/util/PeakBuffer.hxx b/src/util/PeakBuffer.hxx
new file mode 100644
index 000000000..0fbba8d77
--- /dev/null
+++ b/src/util/PeakBuffer.hxx
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_PEAK_BUFFER_HXX
+#define MPD_PEAK_BUFFER_HXX
+
+#include "gcc.h"
+
+#include <stddef.h>
+
+struct fifo_buffer;
+
+/**
+ * A FIFO-like buffer that will allocate more memory on demand to
+ * allow large peaks. This second buffer will be given back to the
+ * kernel when it has been consumed.
+ */
+class PeakBuffer {
+ size_t normal_size, peak_size;
+
+ fifo_buffer *normal_buffer, *peak_buffer;
+
+public:
+ PeakBuffer(size_t _normal_size, size_t _peak_size)
+ :normal_size(_normal_size), peak_size(_peak_size),
+ normal_buffer(nullptr), peak_buffer(nullptr) {}
+
+ PeakBuffer(PeakBuffer &&other)
+ :normal_size(other.normal_size), peak_size(other.peak_size),
+ normal_buffer(other.normal_buffer),
+ peak_buffer(other.peak_buffer) {
+ other.normal_buffer = nullptr;
+ other.peak_buffer = nullptr;
+ }
+
+ ~PeakBuffer();
+
+ PeakBuffer(const PeakBuffer &) = delete;
+ PeakBuffer &operator=(const PeakBuffer &) = delete;
+
+ gcc_pure
+ bool IsEmpty() const;
+
+ const void *Read(size_t *length_r) const;
+ void Consume(size_t length);
+
+ bool Append(const void *data, size_t length);
+};
+
+#endif
diff --git a/src/util/RefCount.hxx b/src/util/RefCount.hxx
new file mode 100644
index 000000000..9a45a585b
--- /dev/null
+++ b/src/util/RefCount.hxx
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ *
+ * A very simple reference counting library.
+ */
+
+#ifndef MPD_REFCOUNT_HXX
+#define MPD_REFCOUNT_HXX
+
+#include <atomic>
+
+class RefCount {
+ std::atomic_uint n;
+
+public:
+ constexpr RefCount():n(1) {}
+
+ void Increment() {
+ ++n;
+ }
+
+ /**
+ * @return true if the number of references has been dropped to 0
+ */
+ bool Decrement() {
+ return --n == 0;
+ }
+};
+
+#endif
diff --git a/src/util/SliceBuffer.hxx b/src/util/SliceBuffer.hxx
new file mode 100644
index 000000000..c61f164f4
--- /dev/null
+++ b/src/util/SliceBuffer.hxx
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_SLICE_BUFFER_HXX
+#define MPD_SLICE_BUFFER_HXX
+
+#include "HugeAllocator.hxx"
+#include "gcc.h"
+
+#include <utility>
+#include <new>
+
+#include <assert.h>
+#include <stddef.h>
+
+/**
+ * This class pre-allocates a certain number of objects, and allows
+ * callers to allocate and free these objects ("slices").
+ */
+template<typename T>
+class SliceBuffer {
+ union Slice {
+ Slice *next;
+
+ T value;
+ };
+
+ /**
+ * The maximum number of slices in this container.
+ */
+ const unsigned n_max;
+
+ /**
+ * The number of slices that are initialized. This is used to
+ * avoid page faulting on the new allocation, so the kernel
+ * does not need to reserve physical memory pages.
+ */
+ unsigned n_initialized;
+
+ /**
+ * The number of slices currently allocated.
+ */
+ unsigned n_allocated;
+
+ Slice *const data;
+
+ /**
+ * Pointer to the first free element in the chain.
+ */
+ Slice *available;
+
+ size_t CalcAllocationSize() const {
+ return n_max * sizeof(Slice);
+ }
+
+public:
+ SliceBuffer(unsigned _count)
+ :n_max(_count), n_initialized(0), n_allocated(0),
+ data((Slice *)HugeAllocate(CalcAllocationSize())),
+ available(nullptr) {
+ assert(n_max > 0);
+ }
+
+ ~SliceBuffer() {
+ /* all slices must be freed explicitly, and this
+ assertion checks for leaks */
+ assert(n_allocated == 0);
+
+ HugeFree(data, CalcAllocationSize());
+ }
+
+ SliceBuffer(const SliceBuffer &other) = delete;
+ SliceBuffer &operator=(const SliceBuffer &other) = delete;
+
+ /**
+ * @return true if buffer allocation (by the constructor) has failed
+ */
+ bool IsOOM() {
+ return data == nullptr;
+ }
+
+ unsigned GetCapacity() const {
+ return n_max;
+ }
+
+ bool IsEmpty() const {
+ return n_allocated == 0;
+ }
+
+ bool IsFull() const {
+ return n_allocated == n_max;
+ }
+
+ template<typename... Args>
+ T *Allocate(Args&&... args) {
+ assert(n_initialized <= n_max);
+ assert(n_allocated <= n_initialized);
+
+ if (available == nullptr) {
+ if (n_initialized == n_max) {
+ /* out of (internal) memory, buffer is full */
+ assert(n_allocated == n_max);
+ return nullptr;
+ }
+
+ available = &data[n_initialized++];
+ available->next = nullptr;
+ }
+
+ /* allocate a slice */
+ T *value = &available->value;
+ available = available->next;
+ ++n_allocated;
+
+ /* construct the object */
+ return ::new((void *)value) T(std::forward<Args>(args)...);
+ }
+
+ void Free(T *value) {
+ assert(n_initialized <= n_max);
+ assert(n_allocated > 0);
+ assert(n_allocated <= n_initialized);
+
+ Slice *slice = reinterpret_cast<Slice *>(value);
+ assert(slice >= data && slice < data + n_max);
+
+ /* destruct the object */
+ value->~T();
+
+ /* insert the slice in the "available" linked list */
+ slice->next = available;
+ available = slice;
+ --n_allocated;
+
+ /* give memory back to the kernel when the last slice
+ was freed */
+ if (n_allocated == 0) {
+ HugeDiscard(data, CalcAllocationSize());
+ n_initialized = 0;
+ available = nullptr;
+ }
+ }
+};
+
+#endif
diff --git a/src/util/bit_reverse.h b/src/util/bit_reverse.h
index e44693b1d..54cb789bb 100644
--- a/src/util/bit_reverse.h
+++ b/src/util/bit_reverse.h
@@ -20,12 +20,13 @@
#ifndef MPD_BIT_REVERSE_H
#define MPD_BIT_REVERSE_H
-#include <glib.h>
+#include "gcc.h"
+
#include <stdint.h>
extern const uint8_t bit_reverse_table[256];
-G_GNUC_CONST
+gcc_const
static inline uint8_t
bit_reverse(uint8_t x)
{
diff --git a/src/util/fifo_buffer.c b/src/util/fifo_buffer.c
new file mode 100644
index 000000000..162ddf946
--- /dev/null
+++ b/src/util/fifo_buffer.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "fifo_buffer.h"
+
+#include <glib.h>
+
+#include <assert.h>
+#include <string.h>
+
+struct fifo_buffer {
+ size_t size, start, end;
+ unsigned char buffer[sizeof(size_t)];
+};
+
+struct fifo_buffer *
+fifo_buffer_new(size_t size)
+{
+ struct fifo_buffer *buffer;
+
+ assert(size > 0);
+
+ buffer = (struct fifo_buffer *)g_malloc(sizeof(*buffer) -
+ sizeof(buffer->buffer) + size);
+
+ buffer->size = size;
+ buffer->start = 0;
+ buffer->end = 0;
+
+ return buffer;
+}
+
+void
+fifo_buffer_init(struct fifo_buffer *buffer, size_t size)
+{
+ buffer->size = size - (sizeof(*buffer) - sizeof(buffer->buffer));
+ buffer->start = 0;
+ buffer->end = 0;
+}
+
+static void
+fifo_buffer_move(struct fifo_buffer *buffer);
+
+struct fifo_buffer *
+fifo_buffer_realloc(struct fifo_buffer *buffer, size_t new_size)
+{
+ if (buffer == NULL)
+ return new_size > 0
+ ? fifo_buffer_new(new_size)
+ : NULL;
+
+ /* existing data must fit in new size */
+ assert(new_size >= buffer->end - buffer->start);
+
+ if (new_size == 0) {
+ fifo_buffer_free(buffer);
+ return NULL;
+ }
+
+ /* compress the buffer when we're shrinking and the tail of
+ the buffer would exceed the new size */
+ if (buffer->end > new_size)
+ fifo_buffer_move(buffer);
+
+ /* existing data must fit in new size: second check */
+ assert(buffer->end <= new_size);
+
+ buffer = g_realloc(buffer, sizeof(*buffer) - sizeof(buffer->buffer) +
+ new_size);
+ buffer->size = new_size;
+ return buffer;
+}
+
+void
+fifo_buffer_free(struct fifo_buffer *buffer)
+{
+ assert(buffer != NULL);
+
+ g_free(buffer);
+}
+
+size_t
+fifo_buffer_capacity(const struct fifo_buffer *buffer)
+{
+ assert(buffer != NULL);
+
+ return buffer->size;
+}
+
+size_t
+fifo_buffer_available(const struct fifo_buffer *buffer)
+{
+ assert(buffer != NULL);
+
+ return buffer->end - buffer->start;
+}
+
+void
+fifo_buffer_clear(struct fifo_buffer *buffer)
+{
+ assert(buffer != NULL);
+
+ buffer->start = 0;
+ buffer->end = 0;
+}
+
+const void *
+fifo_buffer_read(const struct fifo_buffer *buffer, size_t *length_r)
+{
+ assert(buffer != NULL);
+ assert(buffer->end >= buffer->start);
+ assert(length_r != NULL);
+
+ if (buffer->start == buffer->end)
+ /* the buffer is empty */
+ return NULL;
+
+ *length_r = buffer->end - buffer->start;
+ return buffer->buffer + buffer->start;
+}
+
+void
+fifo_buffer_consume(struct fifo_buffer *buffer, size_t length)
+{
+ assert(buffer != NULL);
+ assert(buffer->end >= buffer->start);
+ assert(buffer->start + length <= buffer->end);
+
+ buffer->start += length;
+}
+
+/**
+ * Move data to the beginning of the buffer, to make room at the end.
+ */
+static void
+fifo_buffer_move(struct fifo_buffer *buffer)
+{
+ if (buffer->start == 0)
+ return;
+
+ if (buffer->end > buffer->start)
+ memmove(buffer->buffer,
+ buffer->buffer + buffer->start,
+ buffer->end - buffer->start);
+
+ buffer->end -= buffer->start;
+ buffer->start = 0;
+}
+
+void *
+fifo_buffer_write(struct fifo_buffer *buffer, size_t *max_length_r)
+{
+ assert(buffer != NULL);
+ assert(buffer->end <= buffer->size);
+ assert(max_length_r != NULL);
+
+ if (buffer->end == buffer->size) {
+ fifo_buffer_move(buffer);
+ if (buffer->end == buffer->size)
+ return NULL;
+ } else if (buffer->start > 0 && buffer->start == buffer->end) {
+ buffer->start = 0;
+ buffer->end = 0;
+ }
+
+ *max_length_r = buffer->size - buffer->end;
+ return buffer->buffer + buffer->end;
+}
+
+void
+fifo_buffer_append(struct fifo_buffer *buffer, size_t length)
+{
+ assert(buffer != NULL);
+ assert(buffer->end >= buffer->start);
+ assert(buffer->end + length <= buffer->size);
+
+ buffer->end += length;
+}
+
+bool
+fifo_buffer_is_empty(struct fifo_buffer *buffer)
+{
+ return buffer->start == buffer->end;
+}
+
+bool
+fifo_buffer_is_full(struct fifo_buffer *buffer)
+{
+ return buffer->start == 0 && buffer->end == buffer->size;
+}
diff --git a/src/util/fifo_buffer.h b/src/util/fifo_buffer.h
new file mode 100644
index 000000000..ccea97d86
--- /dev/null
+++ b/src/util/fifo_buffer.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file
+ *
+ * This is a general purpose FIFO buffer library. You may append data
+ * at the end, while another instance reads data from the beginning.
+ * It is optimized for zero-copy usage: you get pointers to the real
+ * buffer, where you may operate on.
+ *
+ * This library is not thread safe.
+ */
+
+#ifndef MPD_FIFO_BUFFER_H
+#define MPD_FIFO_BUFFER_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+struct fifo_buffer;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Creates a new #fifo_buffer object. Free this object with
+ * fifo_buffer_free().
+ *
+ * @param size the size of the buffer in bytes
+ * @return the new #fifo_buffer object
+ */
+struct fifo_buffer *
+fifo_buffer_new(size_t size);
+
+void
+fifo_buffer_init(struct fifo_buffer *buffer, size_t size);
+
+/**
+ * Change the capacity of the #fifo_buffer, while preserving existing
+ * data.
+ *
+ * @param buffer the old buffer, may be NULL
+ * @param new_size the requested new size of the #fifo_buffer; must
+ * not be smaller than the data which is stored in the old buffer
+ * @return the new buffer, may be NULL if the requested new size is 0
+ */
+struct fifo_buffer *
+fifo_buffer_realloc(struct fifo_buffer *buffer, size_t new_size);
+
+/**
+ * Frees the resources consumed by this #fifo_buffer object.
+ */
+void
+fifo_buffer_free(struct fifo_buffer *buffer);
+
+/**
+ * Return the capacity of the buffer, i.e. the size that was passed to
+ * fifo_buffer_new().
+ */
+size_t
+fifo_buffer_capacity(const struct fifo_buffer *buffer);
+
+/**
+ * Return the number of bytes currently stored in the buffer.
+ */
+size_t
+fifo_buffer_available(const struct fifo_buffer *buffer);
+
+/**
+ * Clears all data currently in this #fifo_buffer object. This does
+ * not overwrite the actuall buffer; it just resets the internal
+ * pointers.
+ */
+void
+fifo_buffer_clear(struct fifo_buffer *buffer);
+
+/**
+ * Reads from the beginning of the buffer. To remove consumed data
+ * from the buffer, call fifo_buffer_consume().
+ *
+ * @param buffer the #fifo_buffer object
+ * @param length_r the maximum amount to read is returned here
+ * @return a pointer to the beginning of the buffer, or NULL if the
+ * buffer is empty
+ */
+const void *
+fifo_buffer_read(const struct fifo_buffer *buffer, size_t *length_r);
+
+/**
+ * Marks data at the beginning of the buffer as "consumed".
+ *
+ * @param buffer the #fifo_buffer object
+ * @param length the number of bytes which were consumed
+ */
+void
+fifo_buffer_consume(struct fifo_buffer *buffer, size_t length);
+
+/**
+ * Prepares writing to the buffer. This returns a buffer which you
+ * can write to. To commit the write operation, call
+ * fifo_buffer_append().
+ *
+ * @param buffer the #fifo_buffer object
+ * @param max_length_r the maximum amount to write is returned here
+ * @return a pointer to the end of the buffer, or NULL if the buffer
+ * is already full
+ */
+void *
+fifo_buffer_write(struct fifo_buffer *buffer, size_t *max_length_r);
+
+/**
+ * Commits the write operation initiated by fifo_buffer_write().
+ *
+ * @param buffer the #fifo_buffer object
+ * @param length the number of bytes which were written
+ */
+void
+fifo_buffer_append(struct fifo_buffer *buffer, size_t length);
+
+/**
+ * Checks if the buffer is empty.
+ */
+bool
+fifo_buffer_is_empty(struct fifo_buffer *buffer);
+
+/**
+ * Checks if the buffer is full.
+ */
+bool
+fifo_buffer_is_full(struct fifo_buffer *buffer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/growing_fifo.c b/src/util/growing_fifo.c
index 88431f60e..88431f60e 100644
--- a/src/growing_fifo.c
+++ b/src/util/growing_fifo.c
diff --git a/src/growing_fifo.h b/src/util/growing_fifo.h
index 723c3b3ff..723c3b3ff 100644
--- a/src/growing_fifo.h
+++ b/src/util/growing_fifo.h
diff --git a/src/util/list.h b/src/util/list.h
index fdab47675..73d99befa 100644
--- a/src/util/list.h
+++ b/src/util/list.h
@@ -25,8 +25,6 @@
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H
-#include <glib.h>
-
#ifdef __clang__
/* allow typeof() */
#pragma GCC diagnostic ignored "-Wlanguage-extension-token"
@@ -40,15 +38,15 @@
*
*/
#define container_of(ptr, type, member) \
- (&G_STRUCT_MEMBER(type, ptr, -G_STRUCT_OFFSET(type, member)))
+ ((type *)((uint8_t *)ptr - offsetof(type, member)))
/*
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses
* non-initialized list entries.
*/
-#define LIST_POISON1 ((void *) 0x00100100)
-#define LIST_POISON2 ((void *) 0x00200200)
+#define LIST_POISON1 ((struct list_head *)(void *) 0x00100100)
+#define LIST_POISON2 ((struct list_head *)(void *) 0x00200200)
/*
* Simple doubly linked list implementation.
@@ -82,46 +80,47 @@ static inline void INIT_LIST_HEAD(struct list_head *list)
* the prev/next entries already!
*/
#ifndef CONFIG_DEBUG_LIST
-static inline void __list_add(struct list_head *new,
+static inline void __list_add(struct list_head *new_item,
struct list_head *prev,
struct list_head *next)
{
- next->prev = new;
- new->next = next;
- new->prev = prev;
- prev->next = new;
+ next->prev = new_item;
+ new_item->next = next;
+ new_item->prev = prev;
+ prev->next = new_item;
}
#else
-extern void __list_add(struct list_head *new,
- struct list_head *prev,
- struct list_head *next);
+extern void __list_add(struct list_head *new_item,
+ struct list_head *prev,
+ struct list_head *next);
#endif
/**
* list_add - add a new entry
- * @new: new entry to be added
+ * @new_item: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
-static inline void list_add(struct list_head *new, struct list_head *head)
+static inline void list_add(struct list_head *new_item, struct list_head *head)
{
- __list_add(new, head, head->next);
+ __list_add(new_item, head, head->next);
}
/**
* list_add_tail - add a new entry
- * @new: new entry to be added
+ * @new_item: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
-static inline void list_add_tail(struct list_head *new, struct list_head *head)
+static inline void
+list_add_tail(struct list_head *new_item, struct list_head *head)
{
- __list_add(new, head->prev, head);
+ __list_add(new_item, head->prev, head);
}
/*
@@ -163,23 +162,23 @@ extern void list_del(struct list_head *entry);
/**
* list_replace - replace old entry by new one
* @old : the element to be replaced
- * @new : the new element to insert
+ * @new_item : the new element to insert
*
* If @old was empty, it will be overwritten.
*/
static inline void list_replace(struct list_head *old,
- struct list_head *new)
+ struct list_head *new_item)
{
- new->next = old->next;
- new->next->prev = new;
- new->prev = old->prev;
- new->prev->next = new;
+ new_item->next = old->next;
+ new_item->next->prev = new_item;
+ new_item->prev = old->prev;
+ new_item->prev->next = new_item;
}
static inline void list_replace_init(struct list_head *old,
- struct list_head *new)
+ struct list_head *new_item)
{
- list_replace(old, new);
+ list_replace(old, new_item);
INIT_LIST_HEAD(old);
}
diff --git a/src/utils.c b/src/utils.c
index a2de3212e..776813c4b 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -19,7 +19,6 @@
#include "config.h"
#include "utils.h"
-#include "glib_compat.h"
#include "conf.h"
#include <glib.h>
diff --git a/src/utils.h b/src/utils.h
index f8d6657f2..059d44fa3 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -20,17 +20,7 @@
#ifndef MPD_UTILS_H
#define MPD_UTILS_H
-#include <glib.h>
-#include <stdbool.h>
-
-#ifndef assert_static
-/* Compile time assertion developed by Ralf Holly */
-/* http://pera-software.com/articles/compile-time-assertions.pdf */
-#define assert_static(e) \
- do { \
- enum { assert_static__ = 1/(e) }; \
- } while (0)
-#endif /* !assert_static */
+#include "gerror.h"
char *
parsePath(const char *path, GError **error_r);