esp_ringbuf: Clarify behavior when sending items of 0 size

Ring buffers permit sending items of 0 size where:

- No-split/allow-split buffers will send an item (i.e., header) but the item
will have a 0 sized data section
- Byte buffers will simply return pdTRUE

This commit fixes an incorrect assert w.r.t 0 item size in
xRingbufferSendAcquire() and also adds a note to the API descriptions regarding
0 item sizes. A test case has also been added.
This commit is contained in:
Darian Leung 2023-02-28 15:23:24 +08:00
parent 443d87c2ff
commit a8b9314353
3 changed files with 63 additions and 3 deletions

View File

@ -126,6 +126,10 @@ RingbufHandle_t xRingbufferCreateStatic(size_t xBufferSize,
* the item will occupy will be rounded up to the nearest 32-bit aligned
* size. This is done to ensure all items are always stored in 32-bit
* aligned fashion.
* @note For no-split/allow-split buffers, an xItemSize of 0 will result in
* an item with no data being set (i.e., item only contains the header).
* For byte buffers, an xItemSize of 0 will simply return pdTRUE without
* copying any data.
*
* @return
* - pdTRUE if succeeded
@ -151,6 +155,10 @@ BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer,
* the item will occupy will be rounded up to the nearest 32-bit aligned
* size. This is done to ensure all items are always stored in 32-bit
* aligned fashion.
* @note For no-split/allow-split buffers, an xItemSize of 0 will result in
* an item with no data being set (i.e., item only contains the header).
* For byte buffers, an xItemSize of 0 will simply return pdTRUE without
* copying any data.
*
* @return
* - pdTRUE if succeeded
@ -182,6 +190,8 @@ BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer,
* memory that the item will occupy will be rounded up to the nearest 32-bit
* aligned size. This is done to ensure all items are always stored in 32-bit
* aligned fashion.
* @note An xItemSize of 0 will result in a buffer being acquired, but the buffer
* will have a size of 0.
*
* @return
* - pdTRUE if succeeded
@ -216,6 +226,7 @@ BaseType_t xRingbufferSendComplete(RingbufHandle_t xRingbuffer, void *pvItem);
* @param[in] xTicksToWait Ticks to wait for items in the ring buffer.
*
* @note A call to vRingbufferReturnItem() is required after this to free the item retrieved.
* @note It is possible to receive items with a pxItemSize of 0 on no-split/allow split buffers.
*
* @return
* - Pointer to the retrieved item on success; *pxItemSize filled with the length of the item.
@ -236,6 +247,7 @@ void *xRingbufferReceive(RingbufHandle_t xRingbuffer, size_t *pxItemSize, TickTy
* @note A call to vRingbufferReturnItemFromISR() is required after this to free the item retrieved.
* @note Byte buffers do not allow multiple retrievals before returning an item
* @note Two calls to RingbufferReceiveFromISR() are required if the bytes wrap around the end of the ring buffer.
* @note It is possible to receive items with a pxItemSize of 0 on no-split/allow split buffers.
*
* @return
* - Pointer to the retrieved item on success; *pxItemSize filled with the length of the item.
@ -260,6 +272,7 @@ void *xRingbufferReceiveFromISR(RingbufHandle_t xRingbuffer, size_t *pxItemSize)
*
* @note Call(s) to vRingbufferReturnItem() is required after this to free up the item(s) retrieved.
* @note This function should only be called on allow-split buffers
* @note It is possible to receive items with a pxItemSize of 0 on allow split buffers.
*
* @return
* - pdTRUE if an item (split or unsplit) was retrieved
@ -288,6 +301,7 @@ BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer,
*
* @note Calls to vRingbufferReturnItemFromISR() is required after this to free up the item(s) retrieved.
* @note This function should only be called on allow-split buffers
* @note It is possible to receive items with a pxItemSize of 0 on allow split buffers.
*
* @return
* - pdTRUE if an item (split or unsplit) was retrieved
@ -336,7 +350,7 @@ void *xRingbufferReceiveUpTo(RingbufHandle_t xRingbuffer,
*
* @param[in] xRingbuffer Ring buffer to retrieve the item from
* @param[out] pxItemSize Pointer to a variable to which the size of the retrieved item will be written.
* @param[in] xMaxSize Maximum number of bytes to return.
* @param[in] xMaxSize Maximum number of bytes to return. Size of 0 simply returns NULL.
*
* @note A call to vRingbufferReturnItemFromISR() is required after this to free up the data received.
* @note This function should only be called on byte buffers

View File

@ -982,7 +982,7 @@ BaseType_t xRingbufferSendAcquire(RingbufHandle_t xRingbuffer, void **ppvItem, s
//Check arguments
configASSERT(pxRingbuffer);
configASSERT(ppvItem != NULL || xItemSize == 0);
configASSERT(ppvItem != NULL);
configASSERT((pxRingbuffer->uxRingbufferFlags & (rbBYTE_BUFFER_FLAG | rbALLOW_SPLIT_FLAG)) == 0); //Send acquire currently only supported in NoSplit buffers
*ppvItem = NULL;
@ -1089,7 +1089,7 @@ BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer,
xReturn = pdFALSE;
}
portEXIT_CRITICAL_ISR(&pxRingbuffer->mux);
//Defer notifying the queue set until we are outside the critical section.
if (xNotifyQueueSet == pdTRUE) {
xQueueSendFromISR((QueueHandle_t)pxRingbuffer->xQueueSet, (QueueSetMemberHandle_t *)&pxRingbuffer, pxHigherPriorityTaskWoken);
}

View File

@ -1046,3 +1046,49 @@ TEST_CASE("Test ringbuffer functions work with flash cache disabled", "[esp_ring
TEST_ASSERT( iram_ringbuf_test() );
}
#endif /* !CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH && !CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH */
/* ------------------------ Test ring buffer 0 Item Size -----------------------
* The following test case tests that sending/acquiring an item/bytes of 0 size
* is permissible.
*/
TEST_CASE("Test ringbuffer 0 item size", "[esp_ringbuf]")
{
RingbufHandle_t no_split_rb = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_NOSPLIT);
RingbufHandle_t allow_split_rb = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_ALLOWSPLIT);
RingbufHandle_t byte_rb = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_BYTEBUF);
TEST_ASSERT_MESSAGE(no_split_rb && allow_split_rb && byte_rb, "Failed to create ring buffers");
void *pvItem1;
void *pvItem2;
size_t xItemSize1;
size_t xItemSize2;
//Test that 0 item size on no split buffers should only send a header with no data
TEST_ASSERT_EQUAL(pdTRUE, xRingbufferSend(no_split_rb, NULL, 0, 0));
TEST_ASSERT_NOT_EQUAL(NULL, xRingbufferReceive(no_split_rb, &xItemSize1, 0));
TEST_ASSERT_EQUAL(0, xItemSize1);
//Test that acquiring 0 item size on no split buffers should only send a header without reserving a data buffer
TEST_ASSERT_EQUAL(pdTRUE, xRingbufferSendAcquire(no_split_rb, &pvItem1, 0, 0));
TEST_ASSERT_NOT_EQUAL(NULL, pvItem1);
TEST_ASSERT_EQUAL(pdTRUE, xRingbufferSendComplete(no_split_rb, pvItem1));
TEST_ASSERT_NOT_EQUAL(NULL, xRingbufferReceive(no_split_rb, &xItemSize1, 0));
TEST_ASSERT_EQUAL(0, xItemSize1);
//Test that 0 item size on allow split buffers should only send a header with no data
TEST_ASSERT_EQUAL(pdTRUE, xRingbufferSend(allow_split_rb, NULL, 0, 0));
TEST_ASSERT_EQUAL(pdTRUE, xRingbufferReceiveSplit(allow_split_rb, &pvItem1, &pvItem2, &xItemSize1, &xItemSize2, 0));
TEST_ASSERT_NOT_EQUAL(NULL, pvItem1);
TEST_ASSERT_EQUAL(NULL, pvItem2);
TEST_ASSERT_EQUAL(0, xItemSize1);
//Test that 0 item size on byte buffers should send nothing
TEST_ASSERT_EQUAL(pdTRUE, xRingbufferSend(byte_rb, NULL, 0, 0));
TEST_ASSERT_EQUAL(pdFALSE, xRingbufferReceiveUpTo(byte_rb, &xItemSize1, 0, BUFFER_SIZE));
//Cleanup
vRingbufferDelete(no_split_rb);
vRingbufferDelete(allow_split_rb);
vRingbufferDelete(byte_rb);
}