Skip to content

Commit 597ce3b

Browse files
committed
Merge branch 'bugfix/ringbuf_buflen_bugfix' into 'master'
Bugfix/ringbuf buflen bugfix See merge request !1562
2 parents 61ead8f + 4f33339 commit 597ce3b

File tree

3 files changed

+57
-9
lines changed

3 files changed

+57
-9
lines changed

components/freertos/include/freertos/ringbuf.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ maximum size is (buffer_size/2)-8 bytes. The bytebuf can fill the entire buffer
4444
no overhead.
4545
*/
4646

47+
#include <freertos/queue.h>
48+
4749
//An opaque handle for a ringbuff object.
4850
typedef void * RingbufHandle_t;
4951

@@ -118,6 +120,8 @@ BaseType_t xRingbufferSendFromISR(RingbufHandle_t ringbuf, void *data, size_t da
118120
/**
119121
* @brief Retrieve an item from the ring buffer
120122
*
123+
* @note A call to vRingbufferReturnItem() is required after this to free up the data received.
124+
*
121125
* @param ringbuf - Ring buffer to retrieve the item from
122126
* @param item_size - Pointer to a variable to which the size of the retrieved item will be written.
123127
* @param xTicksToWait - Ticks to wait for items in the ringbuffer.
@@ -131,6 +135,8 @@ void *xRingbufferReceive(RingbufHandle_t ringbuf, size_t *item_size, TickType_t
131135
/**
132136
* @brief Retrieve an item from the ring buffer from an ISR
133137
*
138+
* @note A call to vRingbufferReturnItemFromISR() is required after this to free up the data received
139+
*
134140
* @param ringbuf - Ring buffer to retrieve the item from
135141
* @param item_size - Pointer to a variable to which the size of the retrieved item will be written.
136142
*
@@ -143,6 +149,8 @@ void *xRingbufferReceiveFromISR(RingbufHandle_t ringbuf, size_t *item_size);
143149
/**
144150
* @brief Retrieve bytes from a ByteBuf type of ring buffer, specifying the maximum amount of bytes
145151
* to return
152+
153+
* @note A call to vRingbufferReturnItem() is required after this to free up the data received.
146154
*
147155
* @param ringbuf - Ring buffer to retrieve the item from
148156
* @param item_size - Pointer to a variable to which the size of the retrieved item will be written.
@@ -158,6 +166,8 @@ void *xRingbufferReceiveUpTo(RingbufHandle_t ringbuf, size_t *item_size, TickTyp
158166
* @brief Retrieve bytes from a ByteBuf type of ring buffer, specifying the maximum amount of bytes
159167
* to return. Call this from an ISR.
160168
*
169+
* @note A call to vRingbufferReturnItemFromISR() is required after this to free up the data received
170+
*
161171
* @param ringbuf - Ring buffer to retrieve the item from
162172
* @param item_size - Pointer to a variable to which the size of the retrieved item will be written.
163173
*

components/freertos/ringbuf.c

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,20 @@ static BaseType_t copyItemToRingbufAllowSplit(ringbuf_t *rb, uint8_t *buffer, si
190190
memcpy(rb->write_ptr, buffer, rem_len);
191191
//Update vars so the code later on will write the rest of the data.
192192
buffer+=rem_len;
193-
rbuffer_size-=rem_len;
194193
buffer_size-=rem_len;
194+
//Re-adjust the rbuffer value to be 4 byte aligned
195+
rbuffer_size=(buffer_size+3)&~3;
196+
//It is possible that we are here because we checked for 4byte aligned
197+
//size, but actual data was smaller.
198+
//Eg. For buffer_size = 34, rbuffer_size will be 36. Suppose we had only
199+
//42 bytes of memory available, the top level check will fail, as it will
200+
//check for availability of 36 + 8 = 44 bytes.
201+
//However, the 42 bytes available memory is sufficient for 34 + 8 bytes data
202+
//and so, we can return after writing the data. Hence, this check
203+
if (buffer_size == 0) {
204+
rb->write_ptr=rb->data;
205+
return pdTRUE;
206+
}
195207
} else {
196208
//Huh, only the header fit. Mark as dummy so the receive function doesn't receive
197209
//an useless zero-byte packet.
@@ -286,7 +298,10 @@ static uint8_t *getItemFromRingbufDefault(ringbuf_t *rb, size_t *length, int wan
286298
//...and move the read pointer past the data.
287299
rb->read_ptr+=sizeof(buf_entry_hdr_t)+((hdr->len+3)&~3);
288300
//The buffer will wrap around if we don't have room for a header anymore.
289-
if ((rb->data + rb->size) - rb->read_ptr < sizeof(buf_entry_hdr_t)) {
301+
//Integer typecasting is used because the first operand can result into a -ve
302+
//value for cases wherein the ringbuffer size is not a multiple of 4, but the
303+
//implementation logic aligns read_ptr to 4-byte boundary
304+
if ((int)((rb->data + rb->size) - rb->read_ptr) < (int)sizeof(buf_entry_hdr_t)) {
290305
rb->read_ptr=rb->data;
291306
}
292307
return ret;
@@ -355,12 +370,20 @@ static void returnItemToRingbufDefault(ringbuf_t *rb, void *item) {
355370
rb->free_ptr=rb->data;
356371
} else {
357372
//Skip past item
373+
rb->free_ptr+=sizeof(buf_entry_hdr_t);
374+
//Check if the free_ptr overshoots the buffer.
375+
//Checking this before aligning free_ptr since it is possible that alignment
376+
//will cause pointer to overshoot, if the ringbuf size is not a multiple of 4
377+
configASSERT(rb->free_ptr+hdr->len<=rb->data+rb->size);
378+
//Align free_ptr to 4 byte boundary. Overshoot condition will result in wrap around below
358379
size_t len=(hdr->len+3)&~3;
359-
rb->free_ptr+=len+sizeof(buf_entry_hdr_t);
360-
configASSERT(rb->free_ptr<=rb->data+rb->size);
380+
rb->free_ptr+=len;
361381
}
362382
//The buffer will wrap around if we don't have room for a header anymore.
363-
if ((rb->data+rb->size)-rb->free_ptr < sizeof(buf_entry_hdr_t)) {
383+
//Integer typecasting is used because the first operand can result into a -ve
384+
//value for cases wherein the ringbuffer size is not a multiple of 4, but the
385+
//implementation logic aligns free_ptr to 4-byte boundary
386+
if ((int)((rb->data+rb->size)-rb->free_ptr) < (int)sizeof(buf_entry_hdr_t)) {
364387
rb->free_ptr=rb->data;
365388
}
366389
//The free_ptr can not exceed read_ptr, otherwise write_ptr might overwrite read_ptr.

components/freertos/test/test_ringbuf.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,16 @@ static void uartRxDeinit()
149149
esp_intr_free(s_intr_handle);
150150
}
151151

152-
static void testRingbuffer(int type)
152+
static void testRingbuffer(int type, bool arbitrary)
153153
{
154154
TaskHandle_t th[2];
155155
int i;
156-
rb = xRingbufferCreate(32 * 3, type);
156+
/* Arbitrary Length means buffer length which is not a multiple of 4 */
157+
if (arbitrary) {
158+
rb = xRingbufferCreate(31 * 3, type);
159+
} else {
160+
rb = xRingbufferCreate(32 * 3, type);
161+
}
157162

158163
testtype = TST_MOSTLYFILLED;
159164

@@ -179,12 +184,22 @@ static void testRingbuffer(int type)
179184
// TODO: split this thing into separate orthogonal tests
180185
TEST_CASE("FreeRTOS ringbuffer test, no splitting items", "[freertos]")
181186
{
182-
testRingbuffer(0);
187+
testRingbuffer(0, false);
183188
}
184189

185190
TEST_CASE("FreeRTOS ringbuffer test, w/ splitting items", "[freertos]")
186191
{
187-
testRingbuffer(1);
192+
testRingbuffer(1, false);
193+
}
194+
195+
TEST_CASE("FreeRTOS ringbuffer test, no splitting items, arbitrary length buffer", "[freertos]")
196+
{
197+
testRingbuffer(0, true);
198+
}
199+
200+
TEST_CASE("FreeRTOS ringbuffer test, w/ splitting items, arbitrary length buffer", "[freertos]")
201+
{
202+
testRingbuffer(1, true);
188203
}
189204

190205

0 commit comments

Comments
 (0)