Skip to content

Commit 9b3eda0

Browse files
Merge branch 'fix/ringbuf_receives_item_not_yet_sent' into 'master'
fix(esp_ringbuf): Fixed a bug where in a no-split buffer received items prematurely Closes IDFGH-13694 See merge request espressif/esp-idf!33555
2 parents 6b9242b + 6a82497 commit 9b3eda0

File tree

2 files changed

+88
-3
lines changed

2 files changed

+88
-3
lines changed

components/esp_ringbuf/ringbuf.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,13 @@ static BaseType_t prvCheckItemAvail(Ringbuffer_t *pxRingbuffer)
506506
return pdFALSE; //Byte buffers do not allow multiple retrievals before return
507507
}
508508
if ((pxRingbuffer->xItemsWaiting > 0) && ((pxRingbuffer->pucRead != pxRingbuffer->pucWrite) || (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG))) {
509+
// If the ring buffer is a no-split buffer, the read pointer must point to an item that has been written to.
510+
if ((pxRingbuffer->uxRingbufferFlags & (rbBYTE_BUFFER_FLAG | rbALLOW_SPLIT_FLAG)) == 0) {
511+
ItemHeader_t *pxHeader = (ItemHeader_t *)pxRingbuffer->pucRead;
512+
if ((pxHeader->uxItemFlags & rbITEM_WRITTEN_FLAG) == 0) {
513+
return pdFALSE;
514+
}
515+
}
509516
return pdTRUE; //Items/data available for retrieval
510517
} else {
511518
return pdFALSE; //No items/data available for retrieval
@@ -979,9 +986,6 @@ BaseType_t xRingbufferSendAcquire(RingbufHandle_t xRingbuffer, void **ppvItem, s
979986
if (xItemSize > pxRingbuffer->xMaxItemSize) {
980987
return pdFALSE; //Data will never ever fit in the queue.
981988
}
982-
if ((pxRingbuffer->uxRingbufferFlags & rbBYTE_BUFFER_FLAG) && xItemSize == 0) {
983-
return pdTRUE; //Sending 0 bytes to byte buffer has no effect
984-
}
985989

986990
return prvSendAcquireGeneric(pxRingbuffer, NULL, ppvItem, xItemSize, xTicksToWait);
987991
}

components/esp_ringbuf/test_apps/main/test_ringbuf_common.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,8 @@ size_t continuous_test_string_len(void)
723723
return sizeof(continuous_data);
724724
}
725725

726+
#if !CONFIG_FREERTOS_UNICORE
727+
726728
void send_to_buffer(RingbufHandle_t buffer, size_t max_item_size)
727729
{
728730
for (int iter = 0; iter < SMP_TEST_ITERATIONS; iter++) {
@@ -916,6 +918,8 @@ TEST_CASE("Test static ring buffer SMP", "[esp_ringbuf][linux]")
916918
}
917919
#endif
918920

921+
#endif //!CONFIG_FREERTOS_UNICORE
922+
919923
/* ------------------------ Test ring buffer 0 Item Size -----------------------
920924
* The following test case tests that sending/acquiring an item/bytes of 0 size
921925
* is permissible.
@@ -961,3 +965,80 @@ TEST_CASE("Test ringbuffer 0 item size", "[esp_ringbuf][linux]")
961965
vRingbufferDelete(allow_split_rb);
962966
vRingbufferDelete(byte_rb);
963967
}
968+
969+
/* ---------------------------- Test no-split ring buffer SendAquire and SendComplete ---------------------------
970+
* The following test case tests the SendAquire and SendComplete functions of the no-split ring buffer.
971+
*
972+
* The test case will do the following...
973+
* 1) Create a no-split ring buffer.
974+
* 2) Acquire space on the buffer to send an item.
975+
* 3) Send the item to the buffer.
976+
* 4) Verify that the item is received correctly.
977+
* 5) Acquire space on the buffer until the buffer is full.
978+
* 6) Send the items out-of-order to the buffer.
979+
* 7) Verify that the items are not received until the first item is sent.
980+
* 8) Send the first item.
981+
* 9) Verify that the items are received in the correct order.
982+
*/
983+
TEST_CASE("Test no-split buffers always receive items in order", "[esp_ringbuf][linux]")
984+
{
985+
// Create buffer
986+
RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_NOSPLIT);
987+
TEST_ASSERT_MESSAGE(buffer_handle != NULL, "Failed to create ring buffer");
988+
989+
// Acquire space on the buffer to send an item and write to the item
990+
void *item1;
991+
TEST_ASSERT_EQUAL(pdTRUE, xRingbufferSendAcquire(buffer_handle, &item1, MEDIUM_ITEM_SIZE, TIMEOUT_TICKS));
992+
*(uint32_t *)item1 = 0x123;
993+
994+
// Send the item to the buffer
995+
TEST_ASSERT_EQUAL(pdTRUE, xRingbufferSendComplete(buffer_handle, item1));
996+
997+
// Verify that the item is received correctly
998+
size_t item_size;
999+
uint32_t *received_item = xRingbufferReceive(buffer_handle, &item_size, TIMEOUT_TICKS);
1000+
TEST_ASSERT_NOT_NULL(received_item);
1001+
TEST_ASSERT_EQUAL(item_size, MEDIUM_ITEM_SIZE);
1002+
TEST_ASSERT_EQUAL(*(uint32_t *)received_item, 0x123);
1003+
1004+
// Return the space to the buffer after receiving the item
1005+
vRingbufferReturnItem(buffer_handle, received_item);
1006+
1007+
// At this point, the buffer should be empty
1008+
UBaseType_t items_waiting;
1009+
vRingbufferGetInfo(buffer_handle, NULL, NULL, NULL, NULL, &items_waiting);
1010+
TEST_ASSERT_MESSAGE(items_waiting == 0, "Incorrect items waiting");
1011+
1012+
// Acquire space on the buffer until the buffer is full
1013+
#define MAX_NUM_ITEMS ( BUFFER_SIZE / ( MEDIUM_ITEM_SIZE + ITEM_HDR_SIZE ) )
1014+
void *items[MAX_NUM_ITEMS];
1015+
for (int i = 0; i < MAX_NUM_ITEMS; i++) {
1016+
TEST_ASSERT_EQUAL(pdTRUE, xRingbufferSendAcquire(buffer_handle, &items[i], MEDIUM_ITEM_SIZE, TIMEOUT_TICKS));
1017+
TEST_ASSERT_NOT_NULL(items[i]);
1018+
*(uint32_t *)items[i] = (0x100 + i);
1019+
}
1020+
1021+
// Verify that the buffer is full by attempting to acquire space for another item
1022+
void *another_item;
1023+
TEST_ASSERT_EQUAL(pdFALSE, xRingbufferSendAcquire(buffer_handle, &another_item, MEDIUM_ITEM_SIZE, TIMEOUT_TICKS));
1024+
1025+
// Send the items out-of-order to the buffer. Verify that the items are not received until the first item is sent.
1026+
// In this case, we send the items in the reverse order until the first item is sent.
1027+
for (int i = MAX_NUM_ITEMS - 1; i > 0; i--) {
1028+
TEST_ASSERT_EQUAL(pdTRUE, xRingbufferSendComplete(buffer_handle, items[i]));
1029+
TEST_ASSERT_NULL(xRingbufferReceive(buffer_handle, &item_size, 0));
1030+
}
1031+
1032+
// Send the first item
1033+
TEST_ASSERT_EQUAL(pdTRUE, xRingbufferSendComplete(buffer_handle, items[0]));
1034+
1035+
// Verify that the items are received in the correct order
1036+
for (int i = 0; i < MAX_NUM_ITEMS; i++) {
1037+
received_item = xRingbufferReceive(buffer_handle, &item_size, TIMEOUT_TICKS);
1038+
TEST_ASSERT_EQUAL(*(uint32_t *)received_item, (0x100 + i));
1039+
vRingbufferReturnItem(buffer_handle, received_item);
1040+
}
1041+
1042+
// Cleanup
1043+
vRingbufferDelete(buffer_handle);
1044+
}

0 commit comments

Comments
 (0)