🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

249 lines
6.7 KiB

  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 <cstring>
  22. #include <cstdlib>
  23. #include <climits>
  24. #include <algorithm>
  25. #include "ringbuffer.h"
  26. #include "atomic.h"
  27. #include "threads.h"
  28. #include "almalloc.h"
  29. #include "compat.h"
  30. RingBufferPtr CreateRingBuffer(size_t sz, size_t elem_sz, int limit_writes)
  31. {
  32. size_t power_of_two{0u};
  33. if(sz > 0)
  34. {
  35. power_of_two = sz;
  36. power_of_two |= power_of_two>>1;
  37. power_of_two |= power_of_two>>2;
  38. power_of_two |= power_of_two>>4;
  39. power_of_two |= power_of_two>>8;
  40. power_of_two |= power_of_two>>16;
  41. #if SIZE_MAX > UINT_MAX
  42. power_of_two |= power_of_two>>32;
  43. #endif
  44. }
  45. ++power_of_two;
  46. if(power_of_two < sz) return nullptr;
  47. RingBufferPtr rb{new (al_malloc(16, sizeof(*rb) + power_of_two*elem_sz)) RingBuffer()};
  48. rb->mWriteSize = limit_writes ? sz : (power_of_two-1);
  49. rb->mSizeMask = power_of_two - 1;
  50. rb->mElemSize = elem_sz;
  51. return rb;
  52. }
  53. void RingBuffer::reset() noexcept
  54. {
  55. mWritePtr.store(0, std::memory_order_relaxed);
  56. mReadPtr.store(0, std::memory_order_relaxed);
  57. std::fill_n(mBuffer, (mSizeMask+1)*mElemSize, 0);
  58. }
  59. size_t RingBuffer::readSpace() const noexcept
  60. {
  61. size_t w = mWritePtr.load(std::memory_order_acquire);
  62. size_t r = mReadPtr.load(std::memory_order_acquire);
  63. return (w-r) & mSizeMask;
  64. }
  65. size_t RingBuffer::writeSpace() const noexcept
  66. {
  67. size_t w = mWritePtr.load(std::memory_order_acquire);
  68. size_t r = mReadPtr.load(std::memory_order_acquire) + mWriteSize - mSizeMask;
  69. return (r-w-1) & mSizeMask;
  70. }
  71. size_t RingBuffer::read(void *dest, size_t cnt) noexcept
  72. {
  73. const size_t free_cnt{readSpace()};
  74. if(free_cnt == 0) return 0;
  75. const size_t to_read{std::min(cnt, free_cnt)};
  76. size_t read_ptr{mReadPtr.load(std::memory_order_relaxed) & mSizeMask};
  77. size_t n1, n2;
  78. const size_t cnt2{read_ptr + to_read};
  79. if(cnt2 > mSizeMask+1)
  80. {
  81. n1 = mSizeMask+1 - read_ptr;
  82. n2 = cnt2 & mSizeMask;
  83. }
  84. else
  85. {
  86. n1 = to_read;
  87. n2 = 0;
  88. }
  89. memcpy(dest, mBuffer + read_ptr*mElemSize, n1*mElemSize);
  90. read_ptr += n1;
  91. if(n2 > 0)
  92. {
  93. memcpy(static_cast<char*>(dest) + n1*mElemSize, mBuffer, n2*mElemSize);
  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. memcpy(dest, mBuffer + read_ptr*mElemSize, n1*mElemSize);
  118. if(n2 > 0)
  119. memcpy(static_cast<char*>(dest) + n1*mElemSize, mBuffer, n2*mElemSize);
  120. return to_read;
  121. }
  122. size_t RingBuffer::write(const void *src, size_t cnt) noexcept
  123. {
  124. const size_t free_cnt{writeSpace()};
  125. if(free_cnt == 0) return 0;
  126. const size_t to_write{std::min(cnt, free_cnt)};
  127. size_t write_ptr{mWritePtr.load(std::memory_order_relaxed) & mSizeMask};
  128. size_t n1, n2;
  129. const size_t cnt2{write_ptr + to_write};
  130. if(cnt2 > mSizeMask+1)
  131. {
  132. n1 = mSizeMask+1 - write_ptr;
  133. n2 = cnt2 & mSizeMask;
  134. }
  135. else
  136. {
  137. n1 = to_write;
  138. n2 = 0;
  139. }
  140. memcpy(mBuffer + write_ptr*mElemSize, src, n1*mElemSize);
  141. write_ptr += n1;
  142. if(n2 > 0)
  143. {
  144. memcpy(mBuffer, static_cast<const char*>(src) + n1*mElemSize, n2*mElemSize);
  145. write_ptr += n2;
  146. }
  147. mWritePtr.store(write_ptr, std::memory_order_release);
  148. return to_write;
  149. }
  150. void RingBuffer::readAdvance(size_t cnt) noexcept
  151. {
  152. mReadPtr.fetch_add(cnt, std::memory_order_acq_rel);
  153. }
  154. void RingBuffer::writeAdvance(size_t cnt) noexcept
  155. {
  156. mWritePtr.fetch_add(cnt, std::memory_order_acq_rel);
  157. }
  158. ll_ringbuffer_data_pair RingBuffer::getReadVector() const noexcept
  159. {
  160. ll_ringbuffer_data_pair ret;
  161. size_t w{mWritePtr.load(std::memory_order_acquire)};
  162. size_t r{mReadPtr.load(std::memory_order_acquire)};
  163. w &= mSizeMask;
  164. r &= mSizeMask;
  165. const size_t free_cnt{(w-r) & mSizeMask};
  166. const size_t cnt2{r + free_cnt};
  167. if(cnt2 > mSizeMask+1)
  168. {
  169. /* Two part vector: the rest of the buffer after the current read ptr,
  170. * plus some from the start of the buffer. */
  171. ret.first.buf = const_cast<char*>(&mBuffer[r*mElemSize]);
  172. ret.first.len = mSizeMask+1 - r;
  173. ret.second.buf = const_cast<char*>(mBuffer);
  174. ret.second.len = cnt2 & mSizeMask;
  175. }
  176. else
  177. {
  178. /* Single part vector: just the rest of the buffer */
  179. ret.first.buf = const_cast<char*>(&mBuffer[r*mElemSize]);
  180. ret.first.len = free_cnt;
  181. ret.second.buf = nullptr;
  182. ret.second.len = 0;
  183. }
  184. return ret;
  185. }
  186. ll_ringbuffer_data_pair RingBuffer::getWriteVector() const noexcept
  187. {
  188. ll_ringbuffer_data_pair ret;
  189. size_t w{mWritePtr.load(std::memory_order_acquire)};
  190. size_t r{mReadPtr.load(std::memory_order_acquire) + mWriteSize - mSizeMask};
  191. w &= mSizeMask;
  192. r &= mSizeMask;
  193. const size_t free_cnt{(r-w-1) & mSizeMask};
  194. const size_t cnt2{w + free_cnt};
  195. if(cnt2 > mSizeMask+1)
  196. {
  197. /* Two part vector: the rest of the buffer after the current write ptr,
  198. * plus some from the start of the buffer. */
  199. ret.first.buf = const_cast<char*>(&mBuffer[w*mElemSize]);
  200. ret.first.len = mSizeMask+1 - w;
  201. ret.second.buf = const_cast<char*>(mBuffer);
  202. ret.second.len = cnt2 & mSizeMask;
  203. }
  204. else
  205. {
  206. ret.first.buf = const_cast<char*>(&mBuffer[w*mElemSize]);
  207. ret.first.len = free_cnt;
  208. ret.second.buf = nullptr;
  209. ret.second.len = 0;
  210. }
  211. return ret;
  212. }