321 lines
9.5 KiB
C
Executable File
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
|