ringbuffer.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. #ifndef RINGBUFFER_H
  2. #define RINGBUFFER_H
  3. #include <atomic>
  4. #include <memory>
  5. #include <stddef.h>
  6. #include <utility>
  7. #include "albyte.h"
  8. #include "almalloc.h"
  9. /* NOTE: This lockless ringbuffer implementation is copied from JACK, extended
  10. * to include an element size. Consequently, parameters and return values for a
  11. * size or count is in 'elements', not bytes. Additionally, it only supports
  12. * single-consumer/single-provider operation.
  13. */
  14. struct ll_ringbuffer_data {
  15. al::byte *buf;
  16. size_t len;
  17. };
  18. using ll_ringbuffer_data_pair = std::pair<ll_ringbuffer_data,ll_ringbuffer_data>;
  19. struct RingBuffer {
  20. private:
  21. std::atomic<size_t> mWritePtr{0u};
  22. std::atomic<size_t> mReadPtr{0u};
  23. size_t mWriteSize{0u};
  24. size_t mSizeMask{0u};
  25. size_t mElemSize{0u};
  26. al::FlexArray<al::byte, 16> mBuffer;
  27. public:
  28. RingBuffer(const size_t count) : mBuffer{count} { }
  29. /** Reset the read and write pointers to zero. This is not thread safe. */
  30. void reset() noexcept;
  31. /**
  32. * The non-copying data reader. Returns two ringbuffer data pointers that
  33. * hold the current readable data. If the readable data is in one segment
  34. * the second segment has zero length.
  35. */
  36. ll_ringbuffer_data_pair getReadVector() const noexcept;
  37. /**
  38. * The non-copying data writer. Returns two ringbuffer data pointers that
  39. * hold the current writeable data. If the writeable data is in one segment
  40. * the second segment has zero length.
  41. */
  42. ll_ringbuffer_data_pair getWriteVector() const noexcept;
  43. /**
  44. * Return the number of elements available for reading. This is the number
  45. * of elements in front of the read pointer and behind the write pointer.
  46. */
  47. size_t readSpace() const noexcept
  48. {
  49. const size_t w{mWritePtr.load(std::memory_order_acquire)};
  50. const size_t r{mReadPtr.load(std::memory_order_acquire)};
  51. return (w-r) & mSizeMask;
  52. }
  53. /**
  54. * The copying data reader. Copy at most `cnt' elements into `dest'.
  55. * Returns the actual number of elements copied.
  56. */
  57. size_t read(void *dest, size_t cnt) noexcept;
  58. /**
  59. * The copying data reader w/o read pointer advance. Copy at most `cnt'
  60. * elements into `dest'. Returns the actual number of elements copied.
  61. */
  62. size_t peek(void *dest, size_t cnt) const noexcept;
  63. /** Advance the read pointer `cnt' places. */
  64. void readAdvance(size_t cnt) noexcept
  65. { mReadPtr.fetch_add(cnt, std::memory_order_acq_rel); }
  66. /**
  67. * Return the number of elements available for writing. This is the number
  68. * of elements in front of the write pointer and behind the read pointer.
  69. */
  70. size_t writeSpace() const noexcept
  71. {
  72. const size_t w{mWritePtr.load(std::memory_order_acquire)};
  73. const size_t r{mReadPtr.load(std::memory_order_acquire) + mWriteSize - mSizeMask};
  74. return (r-w-1) & mSizeMask;
  75. }
  76. /**
  77. * The copying data writer. Copy at most `cnt' elements from `src'. Returns
  78. * the actual number of elements copied.
  79. */
  80. size_t write(const void *src, size_t cnt) noexcept;
  81. /** Advance the write pointer `cnt' places. */
  82. void writeAdvance(size_t cnt) noexcept
  83. { mWritePtr.fetch_add(cnt, std::memory_order_acq_rel); }
  84. /**
  85. * Create a new ringbuffer to hold at least `sz' elements of `elem_sz'
  86. * bytes. The number of elements is rounded up to the next power of two
  87. * (even if it is already a power of two, to ensure the requested amount
  88. * can be written).
  89. */
  90. static std::unique_ptr<RingBuffer> Create(size_t sz, size_t elem_sz, int limit_writes);
  91. DEF_FAM_NEWDEL(RingBuffer, mBuffer)
  92. };
  93. using RingBufferPtr = std::unique_ptr<RingBuffer>;
  94. #endif /* RINGBUFFER_H */