/************************************************* 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 #include #include #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; ilist[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