ringbuffer.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 1999-2007 by authors.
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Library General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Library General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Library General Public
  15. * License along with this library; if not, write to the
  16. * Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. * Or go to http://www.gnu.org/copyleft/lgpl.html
  19. */
  20. #include "config.h"
  21. #include "ringbuffer.h"
  22. #include <algorithm>
  23. #include <climits>
  24. #include <cstdint>
  25. #include <stdexcept>
  26. #include "almalloc.h"
  27. RingBufferPtr CreateRingBuffer(size_t sz, size_t elem_sz, int limit_writes)
  28. {
  29. size_t power_of_two{0u};
  30. if(sz > 0)
  31. {
  32. power_of_two = sz;
  33. power_of_two |= power_of_two>>1;
  34. power_of_two |= power_of_two>>2;
  35. power_of_two |= power_of_two>>4;
  36. power_of_two |= power_of_two>>8;
  37. power_of_two |= power_of_two>>16;
  38. #if SIZE_MAX > UINT_MAX
  39. power_of_two |= power_of_two>>32;
  40. #endif
  41. }
  42. ++power_of_two;
  43. if(power_of_two <= sz || power_of_two > std::numeric_limits<size_t>::max()/elem_sz)
  44. throw std::overflow_error{"Ring buffer size overflow"};
  45. const size_t bufbytes{power_of_two * elem_sz};
  46. RingBufferPtr rb{new (FamCount{bufbytes}) RingBuffer{bufbytes}};
  47. rb->mWriteSize = limit_writes ? sz : (power_of_two-1);
  48. rb->mSizeMask = power_of_two - 1;
  49. rb->mElemSize = elem_sz;
  50. return rb;
  51. }
  52. void RingBuffer::reset() noexcept
  53. {
  54. mWritePtr.store(0, std::memory_order_relaxed);
  55. mReadPtr.store(0, std::memory_order_relaxed);
  56. std::fill_n(mBuffer.begin(), (mSizeMask+1)*mElemSize, al::byte{});
  57. }
  58. size_t RingBuffer::readSpace() const noexcept
  59. {
  60. size_t w = mWritePtr.load(std::memory_order_acquire);
  61. size_t r = mReadPtr.load(std::memory_order_acquire);
  62. return (w-r) & mSizeMask;
  63. }
  64. size_t RingBuffer::writeSpace() const noexcept
  65. {
  66. size_t w = mWritePtr.load(std::memory_order_acquire);
  67. size_t r = mReadPtr.load(std::memory_order_acquire) + mWriteSize - mSizeMask;
  68. return (r-w-1) & mSizeMask;
  69. }
  70. size_t RingBuffer::read(void *dest, size_t cnt) noexcept
  71. {
  72. const size_t free_cnt{readSpace()};
  73. if(free_cnt == 0) return 0;
  74. const size_t to_read{std::min(cnt, free_cnt)};
  75. size_t read_ptr{mReadPtr.load(std::memory_order_relaxed) & mSizeMask};
  76. size_t n1, n2;
  77. const size_t cnt2{read_ptr + to_read};
  78. if(cnt2 > mSizeMask+1)
  79. {
  80. n1 = mSizeMask+1 - read_ptr;
  81. n2 = cnt2 & mSizeMask;
  82. }
  83. else
  84. {
  85. n1 = to_read;
  86. n2 = 0;
  87. }
  88. auto outiter = std::copy_n(mBuffer.begin() + read_ptr*mElemSize, n1*mElemSize,
  89. static_cast<al::byte*>(dest));
  90. read_ptr += n1;
  91. if(n2 > 0)
  92. {
  93. std::copy_n(mBuffer.begin(), n2*mElemSize, outiter);
  94. read_ptr += n2;
  95. }
  96. mReadPtr.store(read_ptr, std::memory_order_release);
  97. return to_read;
  98. }
  99. size_t RingBuffer::peek(void *dest, size_t cnt) const noexcept
  100. {
  101. const size_t free_cnt{readSpace()};
  102. if(free_cnt == 0) return 0;
  103. const size_t to_read{std::min(cnt, free_cnt)};
  104. size_t read_ptr{mReadPtr.load(std::memory_order_relaxed) & mSizeMask};
  105. size_t n1, n2;
  106. const size_t cnt2{read_ptr + to_read};
  107. if(cnt2 > mSizeMask+1)
  108. {
  109. n1 = mSizeMask+1 - read_ptr;
  110. n2 = cnt2 & mSizeMask;
  111. }
  112. else
  113. {
  114. n1 = to_read;
  115. n2 = 0;
  116. }
  117. auto outiter = std::copy_n(mBuffer.begin() + read_ptr*mElemSize, n1*mElemSize,
  118. static_cast<al::byte*>(dest));
  119. if(n2 > 0)
  120. std::copy_n(mBuffer.begin(), n2*mElemSize, outiter);
  121. return to_read;
  122. }
  123. size_t RingBuffer::write(const void *src, size_t cnt) noexcept
  124. {
  125. const size_t free_cnt{writeSpace()};
  126. if(free_cnt == 0) return 0;
  127. const size_t to_write{std::min(cnt, free_cnt)};
  128. size_t write_ptr{mWritePtr.load(std::memory_order_relaxed) & mSizeMask};
  129. size_t n1, n2;
  130. const size_t cnt2{write_ptr + to_write};
  131. if(cnt2 > mSizeMask+1)
  132. {
  133. n1 = mSizeMask+1 - write_ptr;
  134. n2 = cnt2 & mSizeMask;
  135. }
  136. else
  137. {
  138. n1 = to_write;
  139. n2 = 0;
  140. }
  141. auto srcbytes = static_cast<const al::byte*>(src);
  142. std::copy_n(srcbytes, n1*mElemSize, mBuffer.begin() + write_ptr*mElemSize);
  143. write_ptr += n1;
  144. if(n2 > 0)
  145. {
  146. std::copy_n(srcbytes + n1*mElemSize, n2*mElemSize, mBuffer.begin());
  147. write_ptr += n2;
  148. }
  149. mWritePtr.store(write_ptr, std::memory_order_release);
  150. return to_write;
  151. }
  152. void RingBuffer::readAdvance(size_t cnt) noexcept
  153. {
  154. mReadPtr.fetch_add(cnt, std::memory_order_acq_rel);
  155. }
  156. void RingBuffer::writeAdvance(size_t cnt) noexcept
  157. {
  158. mWritePtr.fetch_add(cnt, std::memory_order_acq_rel);
  159. }
  160. ll_ringbuffer_data_pair RingBuffer::getReadVector() const noexcept
  161. {
  162. ll_ringbuffer_data_pair ret;
  163. size_t w{mWritePtr.load(std::memory_order_acquire)};
  164. size_t r{mReadPtr.load(std::memory_order_acquire)};
  165. w &= mSizeMask;
  166. r &= mSizeMask;
  167. const size_t free_cnt{(w-r) & mSizeMask};
  168. const size_t cnt2{r + free_cnt};
  169. if(cnt2 > mSizeMask+1)
  170. {
  171. /* Two part vector: the rest of the buffer after the current read ptr,
  172. * plus some from the start of the buffer. */
  173. ret.first.buf = const_cast<al::byte*>(mBuffer.data() + r*mElemSize);
  174. ret.first.len = mSizeMask+1 - r;
  175. ret.second.buf = const_cast<al::byte*>(mBuffer.data());
  176. ret.second.len = cnt2 & mSizeMask;
  177. }
  178. else
  179. {
  180. /* Single part vector: just the rest of the buffer */
  181. ret.first.buf = const_cast<al::byte*>(mBuffer.data() + r*mElemSize);
  182. ret.first.len = free_cnt;
  183. ret.second.buf = nullptr;
  184. ret.second.len = 0;
  185. }
  186. return ret;
  187. }
  188. ll_ringbuffer_data_pair RingBuffer::getWriteVector() const noexcept
  189. {
  190. ll_ringbuffer_data_pair ret;
  191. size_t w{mWritePtr.load(std::memory_order_acquire)};
  192. size_t r{mReadPtr.load(std::memory_order_acquire) + mWriteSize - mSizeMask};
  193. w &= mSizeMask;
  194. r &= mSizeMask;
  195. const size_t free_cnt{(r-w-1) & mSizeMask};
  196. const size_t cnt2{w + free_cnt};
  197. if(cnt2 > mSizeMask+1)
  198. {
  199. /* Two part vector: the rest of the buffer after the current write ptr,
  200. * plus some from the start of the buffer. */
  201. ret.first.buf = const_cast<al::byte*>(mBuffer.data() + w*mElemSize);
  202. ret.first.len = mSizeMask+1 - w;
  203. ret.second.buf = const_cast<al::byte*>(mBuffer.data());
  204. ret.second.len = cnt2 & mSizeMask;
  205. }
  206. else
  207. {
  208. ret.first.buf = const_cast<al::byte*>(mBuffer.data() + w*mElemSize);
  209. ret.first.len = free_cnt;
  210. ret.second.buf = nullptr;
  211. ret.second.len = 0;
  212. }
  213. return ret;
  214. }