Fix the ringbuffer write limit

Previously it just limited the returned write space, irrespective of how much
had already been written. The buffer could still be filled up by doing multiple
writes. Now the size is limited by adjusting the read pointer by the real vs
limited difference when calculating the writable space.
This commit is contained in:
Chris Robinson
2019-01-03 15:54:18 -08:00
parent 88c2f11dcf
commit 21a17620e3
2 changed files with 15 additions and 22 deletions
+14 -21
View File
@@ -52,7 +52,7 @@ RingBufferPtr CreateRingBuffer(size_t sz, size_t elem_sz, int limit_writes)
if(power_of_two < sz) return nullptr;
RingBufferPtr rb{new (al_malloc(16, sizeof(*rb) + power_of_two*elem_sz)) RingBuffer{}};
rb->mSize = limit_writes ? sz : power_of_two;
rb->mWriteSize = limit_writes ? sz : (power_of_two-1);
rb->mSizeMask = power_of_two - 1;
rb->mElemSize = elem_sz;
@@ -77,9 +77,8 @@ size_t RingBuffer::readSpace() const noexcept
size_t RingBuffer::writeSpace() const noexcept
{
size_t w = mWritePtr.load(std::memory_order_acquire);
size_t r = mReadPtr.load(std::memory_order_acquire);
w = (r-w-1) & mSizeMask;
return std::max(w, mSize);
size_t r = mReadPtr.load(std::memory_order_acquire) + mWriteSize - mSizeMask;
return (r-w-1) & mSizeMask;
}
@@ -104,12 +103,11 @@ size_t RingBuffer::read(void *dest, size_t cnt) noexcept
n2 = 0;
}
memcpy(dest, &mBuffer[read_ptr*mElemSize], n1*mElemSize);
memcpy(dest, mBuffer + read_ptr*mElemSize, n1*mElemSize);
read_ptr += n1;
if(n2)
if(n2 > 0)
{
memcpy(static_cast<char*>(dest) + n1*mElemSize, &mBuffer[(read_ptr&mSizeMask)*mElemSize],
n2*mElemSize);
memcpy(static_cast<char*>(dest) + n1*mElemSize, mBuffer, n2*mElemSize);
read_ptr += n2;
}
mReadPtr.store(read_ptr, std::memory_order_release);
@@ -137,13 +135,9 @@ size_t RingBuffer::peek(void *dest, size_t cnt) const noexcept
n2 = 0;
}
memcpy(dest, &mBuffer[read_ptr*mElemSize], n1*mElemSize);
if(n2)
{
read_ptr += n1;
memcpy(static_cast<char*>(dest) + n1*mElemSize, &mBuffer[(read_ptr&mSizeMask)*mElemSize],
n2*mElemSize);
}
memcpy(dest, mBuffer + read_ptr*mElemSize, n1*mElemSize);
if(n2 > 0)
memcpy(static_cast<char*>(dest) + n1*mElemSize, mBuffer, n2*mElemSize);
return to_read;
}
@@ -168,12 +162,11 @@ size_t RingBuffer::write(const void *src, size_t cnt) noexcept
n2 = 0;
}
memcpy(&mBuffer[write_ptr*mElemSize], src, n1*mElemSize);
memcpy(mBuffer + write_ptr*mElemSize, src, n1*mElemSize);
write_ptr += n1;
if(n2)
if(n2 > 0)
{
memcpy(&mBuffer[(write_ptr&mSizeMask)*mElemSize],
static_cast<const char*>(src) + n1*mElemSize, n2*mElemSize);
memcpy(mBuffer, static_cast<const char*>(src) + n1*mElemSize, n2*mElemSize);
write_ptr += n2;
}
mWritePtr.store(write_ptr, std::memory_order_release);
@@ -229,10 +222,10 @@ ll_ringbuffer_data_pair RingBuffer::getWriteVector() const noexcept
ll_ringbuffer_data_pair ret;
size_t w{mWritePtr.load(std::memory_order_acquire)};
size_t r{mReadPtr.load(std::memory_order_acquire)};
size_t r{mReadPtr.load(std::memory_order_acquire) + mWriteSize - mSizeMask};
w &= mSizeMask;
r &= mSizeMask;
const size_t free_cnt{std::min((r-w-1) & mSizeMask, mSize)};
const size_t free_cnt{(r-w-1) & mSizeMask};
const size_t cnt2{w + free_cnt};
if(cnt2 > mSizeMask+1)
+1 -1
View File
@@ -26,7 +26,7 @@ using ll_ringbuffer_data_pair = std::pair<ll_ringbuffer_data,ll_ringbuffer_data>
struct RingBuffer {
std::atomic<size_t> mWritePtr{0u};
std::atomic<size_t> mReadPtr{0u};
size_t mSize{0u};
size_t mWriteSize{0u};
size_t mSizeMask{0u};
size_t mElemSize{0u};