From 4944976e40254bb57337e3544dc067133f140637 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 13 Aug 2012 00:40:00 +0000 Subject: Add Raul::barrier() and remove glib dependency from RingBuffer. Improve RingBuffer performance. git-svn-id: http://svn.drobilla.net/lad/trunk/raul@4674 a436a847-0d15-0410-975c-d299462d15a1 --- raul/Atom.hpp | 4 ---- raul/RingBuffer.hpp | 61 +++++++++++++++++++++++++---------------------------- raul/barrier.hpp | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 36 deletions(-) create mode 100644 raul/barrier.hpp (limited to 'raul') diff --git a/raul/Atom.hpp b/raul/Atom.hpp index 149f78f..6b2ae92 100644 --- a/raul/Atom.hpp +++ b/raul/Atom.hpp @@ -18,13 +18,9 @@ #define RAUL_ATOM_HPP #include -#include -#include #include #include -#include -#include #include namespace Raul { diff --git a/raul/RingBuffer.hpp b/raul/RingBuffer.hpp index 0da93e0..eb86036 100644 --- a/raul/RingBuffer.hpp +++ b/raul/RingBuffer.hpp @@ -22,16 +22,15 @@ #include #include -#include - #include "raul/Noncopyable.hpp" +#include "raul/barrier.hpp" namespace Raul { /** A lock-free RingBuffer. - Thread-safe with a single reader and single writer, and realtime safe + Thread-safe with a single reader and single writer, and real-time safe on both ends. @ingroup raul @@ -66,26 +65,22 @@ public: readers or writers. */ inline void reset() { - g_atomic_int_set(&_write_ptr, 0); - g_atomic_int_set(&_read_ptr, 0); + _write_head = 0; + _read_head = 0; } /** Return the number of bytes of space available for reading. */ inline uint32_t read_space() const { - const uint32_t r = g_atomic_int_get(&_read_ptr); - const uint32_t w = g_atomic_int_get(&_write_ptr); - return read_space_internal(r, w); + return read_space_internal(_read_head, _write_head); } /** Return the number of bytes of space available for writing. */ inline uint32_t write_space() const { - const uint32_t r = g_atomic_int_get(&_read_ptr); - const uint32_t w = g_atomic_int_get(&_write_ptr); - return write_space_internal(r, w); + return write_space_internal(_read_head, _write_head); } /** @@ -97,20 +92,19 @@ public: Read from the RingBuffer without advancing the read head. */ inline uint32_t peek(uint32_t size, void* dst) { - const uint32_t r = g_atomic_int_get(&_read_ptr); - const uint32_t w = g_atomic_int_get(&_write_ptr); - return peek_internal(r, w, size, dst); + return peek_internal(_read_head, _write_head, size, dst); } /** Read from the RingBuffer and advance the read head. */ inline uint32_t read(uint32_t size, void* dst) { - const uint32_t r = g_atomic_int_get(&_read_ptr); - const uint32_t w = g_atomic_int_get(&_write_ptr); + const uint32_t r = _read_head; + const uint32_t w = _write_head; if (peek_internal(r, w, size, dst)) { - g_atomic_int_set(&_read_ptr, (r + size) & _size_mask); + Raul::barrier(); + _read_head = (r + size) & _size_mask; return size; } else { return 0; @@ -121,13 +115,14 @@ public: Skip data in the RingBuffer (advance read head without reading). */ inline uint32_t skip(uint32_t size) { - const uint32_t r = g_atomic_int_get(&_read_ptr); - const uint32_t w = g_atomic_int_get(&_write_ptr); + const uint32_t r = _read_head; + const uint32_t w = _write_head; if (read_space_internal(r, w) < size) { return 0; } - g_atomic_int_set(&_read_ptr, (r + size) & _size_mask); + Raul::barrier(); + _read_head = (r + size) & _size_mask; return size; } @@ -135,22 +130,24 @@ public: Write data to the RingBuffer. */ inline uint32_t write(uint32_t size, const void* src) { - const uint32_t r = g_atomic_int_get(&_read_ptr); - const uint32_t w = g_atomic_int_get(&_write_ptr); + const uint32_t r = _read_head; + const uint32_t w = _write_head; if (write_space_internal(r, w) < size) { return 0; } if (w + size <= _size) { memcpy(&_buf[w], src, size); - g_atomic_int_set(&_write_ptr, (w + size) & _size_mask); + Raul::barrier(); + _write_head = (w + size) & _size_mask; } else { const uint32_t this_size = _size - w; assert(this_size < size); assert(w + this_size <= _size); memcpy(&_buf[w], src, this_size); - memcpy(&_buf[0], (char*)src + this_size, size - this_size); - g_atomic_int_set(&_write_ptr, size - this_size); + memcpy(&_buf[0], (const char*)src + this_size, size - this_size); + Raul::barrier(); + _write_head = size - this_size; } return size; @@ -170,17 +167,17 @@ private: } inline uint32_t write_space_internal(uint32_t r, uint32_t w) const { - if (w > r) { + if (r == w) { + return _size - 1; + } else if (r < w) { return ((r - w + _size) & _size_mask) - 1; - } else if (w < r) { - return (r - w) - 1; } else { - return _size - 1; + return (r - w) - 1; } } inline uint32_t read_space_internal(uint32_t r, uint32_t w) const { - if (w > r) { + if (r < w) { return w - r; } else { return (w - r + _size) & _size_mask; @@ -204,8 +201,8 @@ private: return size; } - mutable uint32_t _write_ptr; ///< Read index into _buf - mutable uint32_t _read_ptr; ///< Write index into _buf + mutable uint32_t _write_head; ///< Read index into _buf + mutable uint32_t _read_head; ///< Write index into _buf const uint32_t _size; ///< Size (capacity) in bytes const uint32_t _size_mask; ///< Mask for fast modulo diff --git a/raul/barrier.hpp b/raul/barrier.hpp new file mode 100644 index 0000000..952278e --- /dev/null +++ b/raul/barrier.hpp @@ -0,0 +1,56 @@ +/* + This file is part of Raul. + Copyright 2012 David Robillard + + Raul 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 3 of the License, or any later version. + + Raul 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 Raul. If not, see . +*/ + +#ifndef RAUL_BARRIER_HPP +#define RAUL_BARRIER_HPP + +#if defined(__APPLE__) +#include + +namespace Raul { +static inline void barrier() { + OSMemoryBarrier(); +} +} + +#elif defined(_WIN32) +#include + +namespace Raul { +static inline void barrier() { + MemoryBarrier(); +} +} + +#elif (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) + +namespace Raul { +static inline void barrier() { + __sync_synchronize(); +} +} + +#else +#pragma message("warning: No memory barriers, possible SMP bugs") + +namespace Raul { +static inline void barrier() { +} +} + +#endif + +#endif // RAUL_BARRIER_HPP -- cgit v1.2.1