fusion/common/ringbuffer/ringbuffer.c

321 lines
9.5 KiB
C
Executable File

/*************************************************
File name : ringbuffer.c
Module : audio and video library functions
Author : amir
Created on : 2022-01-25
Description :
Function implement required by the mutex interface
Modify History:
1. Date: Author: Modification:
202405 罗启宏 增加lock需求
*************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "util.h"
#include "ringbuffer.h"
#include "iot_math.h"
#include "hlog.h"
/**
* @brief
*
* @param size
*
* @return
*/
ringbuffer *ringbuffer_init(uint32_t capacity/*, gfp_t gfp_mask*/)
{
#if 0
/* 检查时候是2的指数倍 */
if (size & (size-1))
{
// size = 1UL << (roundup_pow_of_two(size) + 1);
size = roundup_pow_of_two(size);
}
#endif
ringbuffer *rb = (ringbuffer*)calloc(1, sizeof(ringbuffer));
int8_t *buffer = (int8_t *)malloc(capacity);
if (rb && buffer){
hmutex_init(&rb->mutex);
if (!buffer)
{
free(rb);
rb = NULL;
}else{
rb->capacity = capacity;
rb->buffer = buffer;
INIT_LIST_HEAD(&rb->list[RING_LIST_USING]);
INIT_LIST_HEAD(&rb->list[RING_LIST_FREE]);
ringbuffer_reset(rb);
hsem_init(&rb->sem, 0);
}
}else{
free(rb);
free(buffer);
rb = NULL;
buffer = NULL;
}
return rb;
}
void ringbuffer_deinit(ringbuffer *rb){
hmutex_t mutex = rb->mutex;
ringbuffer_reset(rb);
hmutex_lock(&mutex);
hsem_destroy(&rb->sem);
free(rb->buffer);
free(rb);
hmutex_unlock(&mutex);
hmutex_destroy(&mutex);
}
void ringbuffer_reset(ringbuffer *rb)
{
hmutex_lock(&rb->mutex);
uint16_t i = 0;
for(i=0; i<RING_LIST_MAX; i++){
struct list_head *pos, *n;
list_for_each_safe(pos, n, &rb->list[i]) {
ring_item *item = list_entry(rb->list[i].next, ring_item, link);
list_del(&item->link);
free(item);
}
}
rb->last_drop_seq = UINT32_MAX;
rb->latest_item = NULL;
rb->write = rb->read = rb->buffer;
hmutex_unlock(&rb->mutex);
}
int32_t ringbuffer_size(ringbuffer *rb){
//hloge("rb->write:%u rb->read:%u\n", rb->write, rb->read);
uint32_t size;
hmutex_lock(&rb->mutex);
if (rb->write >= rb->read){
size = (rb->write - rb->read);
}else{
size = rb->capacity - (rb->read - rb->write);
}
hmutex_unlock(&rb->mutex);
return size;
}
int32_t ringbuffer_get_freesize(ringbuffer *rb){
hmutex_lock(&rb->mutex);
uint32_t freesize = rb->write >= rb->read ? rb->capacity - (rb->write - rb->read) : ( rb->read - rb->write);
hmutex_unlock(&rb->mutex);
return freesize;
}
uint32_t ringbuffer_get_lastseq_locked(ringbuffer *rb){
uint32_t seq = rb->latest_item ? rb->latest_item->seq : UINT32_MAX;
return seq;
}
#define ringbuffer_freesize_locked(rb)(\
rb->write >= rb->read ? rb->capacity - (rb->write - rb->read) : ( rb->read - rb->write)\
)
//get the count of items in ringbuffer
int32_t ringbuffer_item_count(ringbuffer *rb){
uint32_t count = 0;
hmutex_lock(&rb->mutex);
struct list_head *pos, *n;
list_for_each_safe(pos, n, &rb->list[RING_LIST_USING]) {
count++;
}
hmutex_unlock(&rb->mutex);
return count;
}
//put in data
ring_item *ringbuffer_put2(ringbuffer *rb, const char *data1, uint32_t data1_size, const char *data2, uint32_t data2_size){
ring_item *item = NULL;
uint32_t total_size = data1_size + data2_size;
if (total_size > rb->capacity){
return item;
}
hmutex_lock(&rb->mutex);
if (list_empty(&rb->list[RING_LIST_FREE])){//if no free item then to malloc one
item = (ring_item *)malloc(sizeof(ring_item));
}else{//get free item
item = list_entry(rb->list[RING_LIST_FREE].next, ring_item, link);
list_del(&item->link);
}
if (item){
//hloge("ringbuffer_put2:%u:%u:%u:%u\n", rb->write, rb->write + total_size, rb->read, rb->buffer + rb->capacity);
if (rb->write == rb->read && rb->read == rb->buffer + rb->capacity ){
rb->write = rb->read = rb->buffer;
//hloge("reset ringbuffer_put2:%u:%u:%u\n", rb->write, rb->read, rb->buffer + rb->capacity);
if (!list_empty(&rb->list[RING_LIST_USING])){
hloge("error RING_LIST_USING should be empty \n\n");
}
}
/*round to remove oldest item until there is enought space to add new one*/
while(!list_empty(&rb->list[RING_LIST_USING]) && ringbuffer_freesize_locked(rb) < total_size){
ring_item *item_oldest = list_entry(rb->list[RING_LIST_USING].next, ring_item, link);
list_del(&item_oldest->link);
list_add_tail(&item_oldest->link, &rb->list[RING_LIST_FREE]);
rb->last_drop_seq = item_oldest->seq;
/*move read to next item.pos*/
ring_item *next = list_entry(rb->list[RING_LIST_USING].next, ring_item, link);
rb->read = next->pos;
}
item->pos = rb->write;//data write here
item->size = total_size;
item->seq = rb->latest_item ? rb->latest_item->seq + 1 : 0; /* +1 */
rb->latest_item = item; /*记录最新的一个, 且不会被删除, 同时seq已是最新的*/
list_add_tail(&item->link, &rb->list[RING_LIST_USING]);
/*buffer---read---write----end*/
/*|---------|-------|--------|*/
/*tail_left = end - write */
uint32_t tail_left = (rb->capacity - (rb->write - rb->buffer));
if (tail_left >= total_size){
memcpy(item->pos, data1, data1_size);
if (data2 && data2_size){
memcpy(item->pos + data1_size, data2, data2_size);
}
rb->write += total_size;
}else{
if (tail_left >= data1_size){
memcpy(item->pos, data1, data1_size);//write to tail
if (data2 && data2_size){
memcpy(item->pos + data1_size, data2, tail_left - data1_size);
memcpy(rb->buffer, data2 + (tail_left - data1_size), data2_size - (tail_left - data1_size));
}
}else{
memcpy(item->pos, data1, tail_left);//write to tail
memcpy(rb->buffer, data1 + tail_left, data1_size - tail_left);
if (data2 && data2_size){
memcpy(rb->buffer + (data1_size - tail_left), data2, data2_size);
}
}
rb->write = rb->buffer + total_size - tail_left;// write = buffer + left
}
hsem_post(&rb->sem);
}
hmutex_unlock(&rb->mutex);
//hloge("rb->write:%p item->size:%u read:%p\n", rb->write, item->size, rb->read);
return item;
}
/**
* @brief
*
* @param rb
* @param to
* @param len
*
* @return success(0) or fail(-1)
*/
int32_t ringbuffer_pop(ringbuffer *rb, char *to, uint32_t *len)
{
int32_t ret = -1;
hmutex_lock(&rb->mutex);
if (!list_empty(&rb->list[RING_LIST_USING])){
ring_item *item = list_entry(rb->list[RING_LIST_USING].next, ring_item, link);
list_del(&item->link);
/*buffer-----read-----write----end*/
/*|---------|---------|----------|*/
/*item->pos + item->size > end ? */
/*then end_pos = item->pos + item->size - end */
const int32_t end_pos = (item->pos + item->size) - (rb->buffer + rb->capacity);/* 如果 end 没到尾 */
if (end_pos <=0){
rb->read = item->pos + item->size;
memcpy(to, item->pos, item->size);
}else{
memcpy(to, item->pos, item->size - end_pos);
memcpy(to + item->size - end_pos, rb->buffer, end_pos);
rb->read = rb->buffer + end_pos;
}
//hloge("ringbuffer_pop end_pos:%d item->size:%u pos:%u, buffer:%u, read:%u\n", end_pos, item->size,item->pos, rb->capacity,rb->read);
if (len){
*len = item->size;
}
list_add_tail(&item->link, &rb->list[RING_LIST_FREE]);
ret = 0;
}
hmutex_unlock(&rb->mutex);
return ret;
}
void ringbuffer_dump(ringbuffer *rb){
uint32_t i = 0;
struct list_head *pos, *n;
hmutex_lock(&rb->mutex);
list_for_each_safe(pos, n, &rb->list[RING_LIST_USING]) {
ring_item *item = list_entry(pos, ring_item, link);
hlogw("%s %02u item:%p size:%u pos:%p seq:%u\n", __func__, i++, item, item->size, item->pos, item->pos);
}
hmutex_unlock(&rb->mutex);
}
/*
* === FUNCTION ======================================================================
* Name: main
* Description:
* =====================================================================================
*/
int32_t ringbuffer_test()
{
#define BUF_SIZE (64)
#define TEST_STR "1234567891234567891234567891234567891234567891234567544656"
char *ssss = malloc(64);
ringbuffer * rb = ringbuffer_init(600);
if (rb == NULL )
{
return -1;
}
int i;
for(i=0; i<10;i++){
ringbuffer_put(rb, TEST_STR, 60);
}
for(i=0; i<10;i++){
uint32_t len;
ringbuffer_pop(rb, ssss, &len);
hlogd("%02d ssss:%s", i, ssss);
}
ringbuffer_dump(rb);
hlogd("1 ringbuffer_test ringbuffer_size:%d\n\n", ringbuffer_size(rb));
for(i=0; i<10;i++){
ringbuffer_put(rb, TEST_STR, 60);
}
hlogd("11 ringbuffer_tes ringbuffer_size:%d\n\n", ringbuffer_size(rb));
for(i=0; i<10;i++){
ringbuffer_put(rb, TEST_STR, 60);
}
ringbuffer_dump(rb);
hlogd("2 ringbuffer_test ringbuffer_size:%d\n\n", ringbuffer_size(rb));
for(i=0; i<10;i++){
uint32_t len;
char outbuf[100]={0};
ringbuffer_pop(rb, outbuf, &len);
hlogd("i:02%d len:%d, outbuf:%s\n", i, len, outbuf);
}
ringbuffer_deinit(rb);
return EXIT_SUCCESS;
}
#if 0
https://blog.csdn.net/u011569253/article/details/71637100
https://www.linuxidc.com/Linux/2016-12/137936.htm
#endif