Merge branch 'feature/ringbuf_improvement' into 'master'

Feature/ringbuf improvement

See merge request !1571
This commit is contained in:
Jeroen Domburg 2017-12-18 16:52:40 +08:00
commit 361bdcf78c
2 changed files with 130 additions and 1 deletions

View File

@ -77,6 +77,19 @@ typedef enum {
*/
RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type);
/**
* @brief Create a ring buffer of type RINGBUF_TYPE_NOSPLIT for a fixed item_size
*
* This API is similar to xRingbufferCreate(), but it will internally allocate
* additional space for the headers.
*
* @param item_size Size of each item to be put into the ring buffer
* @param num_item Maximum number of items the buffer needs to hold simultaneously
*
* @return A RingbufHandle_t handle to the created ringbuffer, or NULL in case of error.
*/
RingbufHandle_t xRingbufferCreateNoSplit(size_t item_size, size_t num_item);
/**
* @brief Delete a ring buffer
*
@ -94,6 +107,38 @@ void vRingbufferDelete(RingbufHandle_t ringbuf);
*/
size_t xRingbufferGetMaxItemSize(RingbufHandle_t ringbuf);
/**
* @brief Get current free size available in the buffer
*
* This gives the real time free space available in the ring buffer. So basically,
* this will be the maximum size of the entry that can be sent into the buffer.
*
* @note This API is not thread safe. So, if multiple threads are accessing the same
* ring buffer, it is the application's responsibility to ensure atomic access to this
* API and the subsequent Send
*
* @param ringbuf - Ring buffer to query
*
* @return Current free size, in bytes, available for an entry
*/
size_t xRingbufferGetCurFreeSize(RingbufHandle_t ringbuf);
/**
* @brief Check if the next item is wrapped
*
* This API tells if the next item that is available for a Receive is wrapped
* or not. This is valid only if the ring buffer type is RINGBUF_TYPE_ALLOWSPLIT
*
* @note This API is not thread safe. So, if multiple threads are accessing the same
* ring buffer, it is the application's responsibility to ensure atomic access to this
* API and the subsequent Receive
*
* @param ringbuf - Ring buffer to query
*
* @return true if the next item is wrapped around
* @return false if the next item is not wrapped
*/
bool xRingbufferIsNextItemWrapped(RingbufHandle_t ringbuf);
/**
* @brief Insert an item into the ring buffer

View File

@ -32,6 +32,7 @@ typedef enum {
typedef enum {
iflag_free = 1, //Buffer is not read and given back by application, free to overwrite
iflag_dummydata = 2, //Data from here to end of ringbuffer is dummy. Restart reading at start of ringbuffer.
iflag_wrap = 4, //Valid for RINGBUF_TYPE_ALLOWSPLIT, indicating that rest of the data is wrapped around
} itemflag_t;
@ -53,6 +54,7 @@ struct ringbuf_t {
BaseType_t (*copyItemToRingbufImpl)(ringbuf_t *rb, uint8_t *buffer, size_t buffer_size);
uint8_t *(*getItemFromRingbufImpl)(ringbuf_t *rb, size_t *length, int wanted_length);
void (*returnItemToRingbufImpl)(ringbuf_t *rb, void *item);
size_t (*getFreeSizeImpl)(ringbuf_t *rb);
};
@ -82,7 +84,6 @@ static int ringbufferFreeMem(ringbuf_t *rb)
return free_size-1;
}
//Copies a single item to the ring buffer; refuses to split items. Assumes there is space in the ringbuffer and
//the ringbuffer is locked. Increases write_ptr to the next item. Returns pdTRUE on
//success, pdFALSE if it can't make the item fit and the calling routine needs to retry
@ -203,6 +204,9 @@ static BaseType_t copyItemToRingbufAllowSplit(ringbuf_t *rb, uint8_t *buffer, si
if (buffer_size == 0) {
rb->write_ptr=rb->data;
return pdTRUE;
} else {
/* Indicate the wrapping */
hdr->flags|=iflag_wrap;
}
} else {
//Huh, only the header fit. Mark as dummy so the receive function doesn't receive
@ -359,6 +363,7 @@ static void returnItemToRingbufDefault(ringbuf_t *rb, void *item) {
configASSERT((hdr->flags & iflag_dummydata)==0);
configASSERT((hdr->flags & iflag_free)==0);
//Mark the buffer as free.
hdr->flags&=~iflag_wrap;
hdr->flags|=iflag_free;
//Do a cleanup pass.
@ -415,6 +420,67 @@ void xRingbufferPrintInfo(RingbufHandle_t ringbuf)
}
size_t xRingbufferGetCurFreeSize(RingbufHandle_t ringbuf)
{
ringbuf_t *rb=(ringbuf_t *)ringbuf;
configASSERT(rb);
configASSERT(rb->getFreeSizeImpl);
int free_size = rb->getFreeSizeImpl(rb);
//Reserve one byte. If we do not do this and the entire buffer is filled, we get a situation
//where read_ptr == free_ptr, messing up the next calculation.
return free_size - 1;
}
static size_t getCurFreeSizeByteBuf(ringbuf_t *rb)
{
//Return whatever space is available depending on relative positions of
//the free pointer and write pointer. There is no overhead of headers in
//this mode
int free_size = rb->free_ptr-rb->write_ptr;
if (free_size <= 0)
free_size += rb->size;
return free_size;
}
static size_t getCurFreeSizeAllowSplit(ringbuf_t *rb)
{
int free_size;
//If Both, the write and free pointer are at the start. Hence, the entire buffer
//is available (minus the space for the header)
if (rb->write_ptr == rb->free_ptr && rb->write_ptr == rb->data) {
free_size = rb->size - sizeof(buf_entry_hdr_t);
} else if (rb->write_ptr < rb->free_ptr) {
//Else if the free pointer is beyond the write pointer, only the space between
//them would be available (minus the space for the header)
free_size = rb->free_ptr - rb->write_ptr - sizeof(buf_entry_hdr_t);
} else {
//Else the data can wrap around and 2 headers will be required
free_size = rb->free_ptr - rb->write_ptr + rb->size - (2 * sizeof(buf_entry_hdr_t));
}
return free_size;
}
static size_t getCurFreeSizeNoSplit(ringbuf_t *rb)
{
int free_size;
//If the free pointer is beyond the write pointer, only the space between
//them would be available
if (rb->write_ptr < rb->free_ptr) {
free_size = rb->free_ptr - rb->write_ptr;
} else {
//Else check which one is bigger amongst the below 2
//1) Space from the write pointer to the end of buffer
int size1 = rb->data + rb->size - rb->write_ptr;
//2) Space from the start of buffer to the free pointer
int size2 = rb->free_ptr - rb->data;
//And then select the larger of the two
free_size = size1 > size2 ? size1 : size2;
}
//In any case, a single header will be used, so subtracting the space that
//would be required for it
return free_size - sizeof(buf_entry_hdr_t);
}
RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type)
{
@ -437,6 +503,7 @@ RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type)
rb->returnItemToRingbufImpl=returnItemToRingbufDefault;
//Calculate max item size. Worst case, we need to split an item into two, which means two headers of overhead.
rb->maxItemSize=rb->size-(sizeof(buf_entry_hdr_t)*2)-4;
rb->getFreeSizeImpl=getCurFreeSizeAllowSplit;
} else if (type==RINGBUF_TYPE_BYTEBUF) {
rb->flags|=flag_bytebuf;
rb->copyItemToRingbufImpl=copyItemToRingbufByteBuf;
@ -444,6 +511,7 @@ RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type)
rb->returnItemToRingbufImpl=returnItemToRingbufBytebuf;
//Calculate max item size. We have no headers and can split anywhere -> size is total size minus one.
rb->maxItemSize=rb->size-1;
rb->getFreeSizeImpl=getCurFreeSizeByteBuf;
} else if (type==RINGBUF_TYPE_NOSPLIT) {
rb->copyItemToRingbufImpl=copyItemToRingbufNoSplit;
rb->getItemFromRingbufImpl=getItemFromRingbufDefault;
@ -453,6 +521,7 @@ RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type)
//(item_data-4) bytes of buffer, then we only have (size-(item_data-4) bytes left to fill
//with the real item. (item size being header+data)
rb->maxItemSize=(rb->size/2)-sizeof(buf_entry_hdr_t)-4;
rb->getFreeSizeImpl=getCurFreeSizeNoSplit;
} else {
configASSERT(0);
}
@ -472,6 +541,12 @@ err:
return NULL;
}
RingbufHandle_t xRingbufferCreateNoSplit(size_t item_size, size_t num_item)
{
size_t aligned_size = (item_size+3)&~3;
return xRingbufferCreate((aligned_size + sizeof(buf_entry_hdr_t)) * num_item, RINGBUF_TYPE_NOSPLIT);
}
void vRingbufferDelete(RingbufHandle_t ringbuf) {
ringbuf_t *rb=(ringbuf_t *)ringbuf;
if (rb) {
@ -489,6 +564,15 @@ size_t xRingbufferGetMaxItemSize(RingbufHandle_t ringbuf)
return rb->maxItemSize;
}
bool xRingbufferIsNextItemWrapped(RingbufHandle_t ringbuf)
{
ringbuf_t *rb=(ringbuf_t *)ringbuf;
configASSERT(rb);
buf_entry_hdr_t *hdr=(buf_entry_hdr_t *)rb->read_ptr;
return hdr->flags & iflag_wrap;
}
BaseType_t xRingbufferSend(RingbufHandle_t ringbuf, void *data, size_t dataSize, TickType_t ticks_to_wait)
{
ringbuf_t *rb=(ringbuf_t *)ringbuf;