diff options
-rw-r--r-- | raul/Atom.hpp | 4 | ||||
-rw-r--r-- | raul/RingBuffer.hpp | 61 | ||||
-rw-r--r-- | raul/barrier.hpp | 56 | ||||
-rw-r--r-- | test/ringbuffer_test.cpp | 1 |
4 files changed, 86 insertions, 36 deletions
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 <stdint.h> -#include <glib.h> -#include <cassert> #include <cstdlib> #include <cstring> -#include <iostream> -#include <map> #include <string> 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 <stdlib.h> #include <string.h> -#include <glib.h> - #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 <http://drobilla.net> + + 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 <http://www.gnu.org/licenses/>. +*/ + +#ifndef RAUL_BARRIER_HPP +#define RAUL_BARRIER_HPP + +#if defined(__APPLE__) +#include <libkern/OSAtomic.h> + +namespace Raul { +static inline void barrier() { + OSMemoryBarrier(); +} +} + +#elif defined(_WIN32) +#include <windows.h> + +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 diff --git a/test/ringbuffer_test.cpp b/test/ringbuffer_test.cpp index 38e09e9..48f5431 100644 --- a/test/ringbuffer_test.cpp +++ b/test/ringbuffer_test.cpp @@ -14,6 +14,7 @@ along with Raul. If not, see <http://www.gnu.org/licenses/>. */ +#include <climits> #include <cstdio> #include <cstdlib> #include <cstring> |